File: Color.cpp

package info (click to toggle)
0ad 0.0.26-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 130,460 kB
  • sloc: cpp: 261,824; ansic: 198,392; javascript: 19,067; python: 14,557; sh: 7,629; perl: 4,072; xml: 849; makefile: 741; java: 533; ruby: 229; php: 190; pascal: 30; sql: 21; tcl: 4
file content (146 lines) | stat: -rw-r--r-- 3,722 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* Copyright (C) 2022 Wildfire Games.
 * This file is part of 0 A.D.
 *
 * 0 A.D. is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * 0 A.D. is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "precompiled.h"

#include "graphics/Color.h"

#include "graphics/SColor.h"
#include "lib/sysdep/arch/x86_x64/simd.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"

#if COMPILER_HAS_SSE
#include <xmmintrin.h>
#endif

static SColor4ub ConvertRGBColorTo4ubFallback(const RGBColor& src)
{
	SColor4ub result;
	result.R = Clamp(static_cast<int>(src.X * 255), 0, 255);
	result.G = Clamp(static_cast<int>(src.Y * 255), 0, 255);
	result.B = Clamp(static_cast<int>(src.Z * 255), 0, 255);
	result.A = 255;
	return result;
}

// on IA32, this is replaced by an SSE assembly version in ia32.cpp
SColor4ub (*ConvertRGBColorTo4ub)(const RGBColor& src) = ConvertRGBColorTo4ubFallback;


// Assembler-optimized function for color conversion
#if COMPILER_HAS_SSE
static SColor4ub ConvertRGBColorTo4ubSSE(const RGBColor& src)
{
	const __m128 zero = _mm_setzero_ps();
	const __m128 _255 = _mm_set_ss(255.0f);
	__m128 r = _mm_load_ss(&src.X);
	__m128 g = _mm_load_ss(&src.Y);
	__m128 b = _mm_load_ss(&src.Z);

	// C = min(255, 255*max(C, 0)) ( == Clamp(255*C, 0, 255) )
	r = _mm_max_ss(r, zero);
	g = _mm_max_ss(g, zero);
	b = _mm_max_ss(b, zero);

	r = _mm_mul_ss(r, _255);
	g = _mm_mul_ss(g, _255);
	b = _mm_mul_ss(b, _255);

	r = _mm_min_ss(r, _255);
	g = _mm_min_ss(g, _255);
	b = _mm_min_ss(b, _255);

	// convert to integer and combine channels using bit logic
	int ri = _mm_cvtss_si32(r);
	int gi = _mm_cvtss_si32(g);
	int bi = _mm_cvtss_si32(b);

	return SColor4ub(ri, gi, bi, 0xFF);
}
#endif

void ColorActivateFastImpl()
{
#if COMPILER_HAS_SSE
	if (HostHasSSE())
	{
		ConvertRGBColorTo4ub = ConvertRGBColorTo4ubSSE;
		return;
	}
#elif defined(ARCH_X86_64)
	debug_printf("No SSE available. Slow fallback routines will be used.\n");
#endif
}

/**
 * Important: This function does not modify the value if parsing fails.
 */
bool CColor::ParseString(const CStr8& value, int defaultAlpha)
{
	const size_t NUM_VALS = 4;
	int values[NUM_VALS] = { 0, 0, 0, defaultAlpha };
	std::stringstream stream;
	stream.str(value);
	// Parse each value
	size_t i;
	for (i = 0; i < NUM_VALS; ++i)
	{
		if (stream.eof())
			break;

		stream >> values[i];
		if ((stream.rdstate() & std::stringstream::failbit) != 0)
		{
			LOGWARNING("Unable to parse CColor parameters. Your input: '%s'", value.c_str());
			return false;
		}
		if (values[i] < 0 || values[i] > 255)
		{
			LOGWARNING("Invalid value (<0 or >255) when parsing CColor parameters. Your input: '%s'", value.c_str());
			return false;
		}
	}

	if (i < 3)
	{
		LOGWARNING("Not enough parameters when parsing as CColor. Your input: '%s'", value.c_str());
		return false;
	}
	if (!stream.eof())
	{
		LOGWARNING("Too many parameters when parsing as CColor. Your input: '%s'", value.c_str());
		return false;
	}

	r = values[0] / 255.f;
	g = values[1] / 255.f;
	b = values[2] / 255.f;
	a = values[3] / 255.f;

	return true;
}

bool CColor::operator==(const CColor& color) const
{
	return
		r == color.r &&
		g == color.g &&
		b == color.b &&
		a == color.a;
}