1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/misc/rgba.h"
23 #include "nel/misc/stream.h"
24 #include "nel/misc/system_info.h"
25 #include "nel/misc/common.h"
34 #define DISABLE_MMX_OPTIM
37 // ***************************************************************************
38 // ***************************************************************************
40 // ***************************************************************************
41 // ***************************************************************************
46 const CRGBA
CRGBA::Black(0, 0, 0) ;
47 const CRGBA
CRGBA::Red(255, 0, 0) ;
48 const CRGBA
CRGBA::Green(0, 255, 0) ;
49 const CRGBA
CRGBA::Yellow(255, 255, 0) ;
50 const CRGBA
CRGBA::Blue(0, 0, 255) ;
51 const CRGBA
CRGBA::Magenta(255, 0, 255) ;
52 const CRGBA
CRGBA::Cyan(0, 255, 255) ;
53 const CRGBA
CRGBA::White(255, 255, 255) ;
54 const CRGBA
CRGBA::Transparent(0, 0, 0, 0);
56 // ***************************************************************************
57 void CRGBA::serial(NLMISC::IStream
&f
)
64 // ***************************************************************************
65 void CRGBA::set(uint8 r
, uint8 g
, uint8 b
, uint8 a
)
72 // ***************************************************************************
73 uint8
CRGBA::toGray() const
75 return (R
*11+G
*16+B
*5)/32;
79 #pragma warning(disable : 4731) /* frame pointer register 'ebp' modified by inline assembly code */
82 // ***************************************************************************
83 void CRGBA::addColors(CRGBA
*dest
, const CRGBA
*src1
, const CRGBA
*src2
, uint numColors
, uint srcStride
, uint destStride
, uint dup
)
85 if (numColors
== 0) return;
86 #if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)
87 if (!CSystemInfo::hasMMX())
89 { // unoptimized version
94 dest
->add(*src1
, *src2
);
95 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
96 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
97 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
102 if (dup
== 4) // optimisation for the 4 case
106 dest
->add(*src1
, *src2
);
107 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
108 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
109 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
110 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
111 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
112 dest
= (CRGBA
*) ((uint8
*) dest
+ (destStride
<< 1));
114 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
115 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
122 dest
->add(*src1
, *src2
);
127 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
128 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
132 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
133 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
134 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
139 #if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)
140 else // optimized mmx version
142 /// well, this could be further optimized when stride is 4 (2 at once)
151 sub ebx
, esi
; offset to source
2
159 movd mm1
, [esi
+ ebx
]
179 sub ebx
, esi
; offset to source
2
185 movd mm1
, [esi
+ ebx
]
191 mov
[edi
+ 2 * edx
], eax
192 lea edi
, [edi
+ edx
* 2]
194 lea edi
, [edi
+ edx
* 2]
211 sub ebx
, esi
; offset to source
2
219 movd mm1
, [esi
+ ebx
]
229 pop ecx
; get back the loop counter
243 // ***************************************************************************
244 void CRGBA::modulateColors(CRGBA
*dest
, const CRGBA
*src1
, const CRGBA
*src2
, uint numColors
, uint srcStride
, uint destStride
, uint dup
)
246 #if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)
247 if (!CSystemInfo::hasMMX())
249 { // unoptimized version
254 dest
->modulateFromColor(*src1
, *src2
);
255 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
256 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
257 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
262 if (dup
== 4) // optimisation for the 4 case
266 dest
->modulateFromColor(*src1
, *src2
);
267 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
268 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
269 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
270 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
271 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
272 dest
= (CRGBA
*) ((uint8
*) dest
+ (destStride
<< 1));
274 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
275 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
282 dest
->modulateFromColor(*src1
, *src2
);
287 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
288 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
292 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
293 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
294 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
299 #if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)
300 else // optimized mmx version
303 /// well, this could be further optimized when stride is 4
313 sub ebx
, esi
; offset to source
2
319 movd mm1
, [esi
+ ebx
]
347 sub ebx
, esi
; offset to source
2
353 movd mm1
, [esi
+ ebx
]
360 ; duplicate the result
4 times
363 mov
[edi
+ 2 * edx
], eax
364 lea edi
, [edi
+ 2 * edx
]
366 lea edi
, [edi
+ 2 * edx
]
383 sub ebx
, esi
; offset to source
2
391 movd mm1
, [esi
+ ebx
]
405 pop ecx
; get back the loop counter
419 // ***************************************************************************
420 void CRGBA::subtractColors(CRGBA
*dest
, const CRGBA
*src1
, const CRGBA
*src2
, uint numColors
, uint srcStride
, uint destStride
, uint dup
)
422 if (numColors
== 0) return;
423 #if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)
424 if (!CSystemInfo::hasMMX())
426 { // unoptimized version
431 dest
->sub(*src1
, *src2
);
432 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
433 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
434 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
439 if (dup
== 4) // optimisation for the 4 case
443 dest
->sub(*src1
, *src2
);
444 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
445 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
446 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
447 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
448 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
449 dest
= (CRGBA
*) ((uint8
*) dest
+ (destStride
<< 1));
451 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
452 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
459 dest
->sub(*src1
, *src2
);
464 * (CRGBA
*) ((uint8
*) dest
+ destStride
) = *dest
;
465 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
469 dest
= (CRGBA
*) ((uint8
*) dest
+ destStride
);
470 src1
= (CRGBA
*) ((uint8
*) src1
+ srcStride
);
471 src2
= (CRGBA
*) ((uint8
*) src2
+ srcStride
);
476 #if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)
477 else // optimized mmx version
479 /// well, this could be further optimized when stride is 4 (2 at once)
488 sub ebx
, esi
; offset to source
2
496 movd mm1
, [esi
+ ebx
]
516 sub ebx
, esi
; offset to source
2
522 movd mm1
, [esi
+ ebx
]
528 mov
[edi
+ 2 * edx
], eax
529 lea edi
, [edi
+ edx
* 2]
531 lea edi
, [edi
+ edx
* 2]
548 sub ebx
, esi
; offset to source
2
556 movd mm1
, [esi
+ ebx
]
566 pop ecx
; get back the loop counter
580 // ***************************************************************************
581 // ***************************************************************************
583 // ***************************************************************************
584 // ***************************************************************************
587 // ***************************************************************************
588 void CBGRA::serial(NLMISC::IStream
&f
)
596 // ***************************************************************************
597 void CBGRA::set(uint8 r
, uint8 g
, uint8 b
, uint8 a
)
605 // ***************************************************************************
606 void CBGRA::blendFromui(CBGRA
&c0
, CBGRA
&c1
, uint coef
) // coef must be in [0,256]
610 R
= (c0
.R
*a2
+ c1
.R
*a1
) >>8;
611 G
= (c0
.G
*a2
+ c1
.G
*a1
) >>8;
612 B
= (c0
.B
*a2
+ c1
.B
*a1
) >>8;
613 A
= (c0
.A
*a2
+ c1
.A
*a1
) >>8;
616 // ***************************************************************************
617 bool CRGBA::convertToHLS(float &h
, float &l
, float &s
) const
623 float maxV
= NLMISC::maxof(r
, g
, b
);
624 float minV
= NLMISC::minof(r
, g
, b
);
626 // all composants are equals -> achromatique
636 l
= 0.5f
* (maxV
+ minV
);
638 float diff
= maxV
- minV
;
641 s
= l
> 0.5f
? /*are we in the top of the double-hexcone ? */
642 diff
/ (2.f
- maxV
- minV
) :
643 diff
/ (maxV
+ minV
);
652 h
= 2.f
+ (b
- r
) / diff
;
654 #if defined(GCC_VERSION) && (GCC_VERSION == 40204)
655 // use the fix only if using the specific GCC version
658 h
= 4.f
+ (r
- g
) / diff
;
662 // this case is to fix a compiler bug
668 h
= 4.f
+ (r
- g
) / diff
;
672 h
*= 60.f
; // scale to [0..360]
674 if (h
< 0.f
) h
+= 360.f
;
679 // ***************************************************************************
680 /// Used by buildFromHLS
681 static float HLSValue(float h
, float v1
, float v2
)
683 /* get hue in the [0, 360] interval */
684 // h -= 360.f * ::floorf(h / 360.f);
686 if (h
> 360.f
) h
-= 360.f
;
687 else if (h
< 0) h
+= 360.f
;
691 return v1
+ (v2
- v1
) * h
/ 60.f
;
699 return v1
+ (v2
- v1
) * (240.f
- h
) / 60.f
;
708 // ***************************************************************************
709 void CRGBA::buildFromHLS(float h
, float l
, float s
)
714 float v2
= (l
<= 0.5f
) ? (l
* (1.f
+ s
)) : (l
+ s
- l
* s
);
715 float v1
= 2.f
* l
- v2
;
717 if (s
== 0) // achromatic ?
719 R
= G
= B
= (uint8
) (255.f
* l
);
721 else // chromatic case
725 v
= HLSValue(h
+ 120.f
, v1
, v2
);
727 R
= (uint8
) (255.f
* v
);
729 v
= HLSValue(h
, v1
, v2
);
731 G
= (uint8
) (255.f
* v
);
733 v
= HLSValue(h
- 120.f
, v1
, v2
);
735 B
= (uint8
) (255.f
* v
);
739 CRGBA
CRGBA::stringToRGBA( const char *ptr
)
743 int r
= 255, g
= 255, b
= 255, a
= 255;
745 // we need at least 3 integer values to consider string is valid
746 if (sscanf( ptr
, "%d %d %d %d", &r
, &g
, &b
, &a
) >= 3)
753 return CRGBA( r
,g
,b
,a
);
756 // we need at least 3 hexadecimal values to consider string is valid
757 if (sscanf(ptr
, "#%02x%02x%02x%02x", &r
, &g
, &b
, &a
) >= 3)
764 return CRGBA(r
, g
, b
, a
);
768 return NLMISC::CRGBA::White
;
771 std::string
CRGBA::toString() const
774 s
= NLMISC::toString( R
);
776 s
+= NLMISC::toString( G
);
778 s
+= NLMISC::toString( B
);
780 s
+= NLMISC::toString( A
);
784 bool CRGBA::fromString( const std::string
&s
)
786 *this = stringToRGBA( s
.c_str() );
791 // ***************************************************************************
792 // ***************************************************************************
794 // ***************************************************************************
795 // ***************************************************************************
798 // ***************************************************************************
799 void CRGBAF::serial(NLMISC::IStream
&f
)
806 // ***************************************************************************
807 void CRGBAF::set(float r
, float g
, float b
, float a
)