Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / misc / rgba.cpp
blob4db5846bc6870e62120fd5f41f1ddde23f00bc46
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
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/>.
20 #include "stdmisc.h"
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"
27 #ifdef DEBUG_NEW
28 #define new DEBUG_NEW
29 #endif
31 namespace NLMISC {
33 #ifdef NL_NO_ASM
34 #define DISABLE_MMX_OPTIM
35 #endif
37 // ***************************************************************************
38 // ***************************************************************************
39 // CRGBA
40 // ***************************************************************************
41 // ***************************************************************************
43 // predifined colors
45 /// some colors
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)
59 f.serial (R);
60 f.serial (G);
61 f.serial (B);
62 f.serial (A);
64 // ***************************************************************************
65 void CRGBA::set(uint8 r, uint8 g, uint8 b, uint8 a)
67 R = r;
68 G = g;
69 B = b;
70 A = a;
72 // ***************************************************************************
73 uint8 CRGBA::toGray() const
75 return (R*11+G*16+B*5)/32;
78 #ifdef NL_OS_WINDOWS
79 #pragma warning(disable : 4731) /* frame pointer register 'ebp' modified by inline assembly code */
80 #endif
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())
88 #endif
89 { // unoptimized version
90 if (dup == 1)
92 while (numColors--)
94 dest->add(*src1, *src2);
95 dest = (CRGBA *) ((uint8 *) dest + destStride);
96 src1 = (CRGBA *) ((uint8 *) src1 + srcStride);
97 src2 = (CRGBA *) ((uint8 *) src2 + srcStride);
100 else
102 if (dup == 4) // optimisation for the 4 case
104 while (numColors--)
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);
118 else
120 while (numColors--)
122 dest->add(*src1, *src2);
124 uint k = dup - 1;
127 * (CRGBA *) ((uint8 *) dest + destStride) = *dest;
128 dest = (CRGBA *) ((uint8 *) dest + destStride);
130 while (--k);
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)
143 if (dup == 1)
145 __asm
147 push ebp
148 mov edi, dest
149 mov esi, src1
150 mov ebx, src2
151 sub ebx, esi ; offset to source 2
152 mov ecx, numColors
153 mov edx, destStride
154 mov ebp, srcStride
155 sub edi, edx
156 myLoop:
157 movd mm0, [esi]
158 add edi, edx
159 movd mm1, [esi + ebx]
160 paddusb mm0, mm1
161 movd [edi], mm0
162 add esi, ebp
163 dec ecx
164 jne myLoop
165 pop ebp
166 emms
169 else
171 if (dup == 4)
173 __asm
175 push ebp
176 mov edi, dest
177 mov esi, src1
178 mov ebx, src2
179 sub ebx, esi ; offset to source 2
180 mov ecx, numColors
181 mov edx, destStride
182 mov ebp, srcStride
183 myLoop4:
184 movd mm0, [esi]
185 movd mm1, [esi + ebx]
186 paddusb mm0, mm1
187 movd eax, mm0
189 mov [edi], eax
190 mov [edi + edx], eax
191 mov [edi + 2 * edx], eax
192 lea edi, [edi + edx * 2]
193 mov [edi + edx], eax
194 lea edi, [edi + edx * 2]
195 add esi, ebp
197 dec ecx
198 jne myLoop4
199 pop ebp
200 emms
203 else
205 __asm
207 push ebp
208 mov edi, dest
209 mov esi, src1
210 mov ebx, src2
211 sub ebx, esi ; offset to source 2
212 mov ecx, numColors
213 mov edx, destStride
214 mov eax, dup
215 mov ebp, srcStride
216 push eax
217 myLoopN:
218 movd mm0, [esi]
219 movd mm1, [esi + ebx]
220 push ecx
221 paddusb mm0, mm1
222 mov ecx, 4[esp]
223 movd eax, mm0
224 dupLoopN:
225 mov [edi], eax
226 dec ecx
227 lea edi, [edi + edx]
228 jne dupLoopN
229 pop ecx ; get back the loop counter
230 add esi, ebp
231 dec ecx
232 jne myLoopN
233 pop eax
234 pop ebp
235 emms
240 #endif
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())
248 #endif
249 { // unoptimized version
250 if (dup == 1)
252 while (numColors--)
254 dest->modulateFromColor(*src1, *src2);
255 dest = (CRGBA *) ((uint8 *) dest + destStride);
256 src1 = (CRGBA *) ((uint8 *) src1 + srcStride);
257 src2 = (CRGBA *) ((uint8 *) src2 + srcStride);
260 else
262 if (dup == 4) // optimisation for the 4 case
264 while (numColors--)
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);
278 else
280 while (numColors--)
282 dest->modulateFromColor(*src1, *src2);
284 uint k = dup - 1;
287 * (CRGBA *) ((uint8 *) dest + destStride) = *dest;
288 dest = (CRGBA *) ((uint8 *) dest + destStride);
290 while (--k);
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
302 uint64 blank = 0;
303 /// well, this could be further optimized when stride is 4
304 if (dup == 1)
306 __asm
308 push ebp
309 movq mm2, blank
310 mov edi, dest
311 mov esi, src1
312 mov ebx, src2
313 sub ebx, esi ; offset to source 2
314 mov ecx, numColors
315 mov edx, destStride
316 mov ebp, srcStride
317 myLoop:
318 movd mm0, [esi]
319 movd mm1, [esi + ebx]
320 punpcklbw mm0, mm2
321 punpcklbw mm1, mm2
322 pmullw mm0, mm1
323 psrlw mm0, 8
324 packuswb mm0, mm0
325 movd [edi], mm0
326 add edi, edx
327 add esi, ebp
329 dec ecx
330 jne myLoop
331 pop ebp
332 emms
335 else
337 if (dup == 4)
340 __asm
342 push ebp
343 movq mm2, blank
344 mov edi, dest
345 mov esi, src1
346 mov ebx, src2
347 sub ebx, esi ; offset to source 2
348 mov ecx, numColors
349 mov edx, destStride
350 mov ebp, srcStride
351 myLoop4:
352 movd mm0, [esi]
353 movd mm1, [esi + ebx]
354 punpcklbw mm0, mm2
355 punpcklbw mm1, mm2
356 pmullw mm0, mm1
357 psrlw mm0, 8
358 packuswb mm0, mm0
359 movd eax, mm0
360 ; duplicate the result 4 times
361 mov [edi], eax
362 mov [edi + edx], eax
363 mov [edi + 2 * edx], eax
364 lea edi, [edi + 2 * edx]
365 mov [edi + edx], eax
366 lea edi, [edi + 2 * edx]
367 add esi, ebp
368 dec ecx
369 jne myLoop4
370 pop ebp
371 emms
374 else
376 __asm
378 push ebp
379 movq mm2, blank
380 mov edi, dest
381 mov esi, src1
382 mov ebx, src2
383 sub ebx, esi ; offset to source 2
384 mov ecx, numColors
385 mov edx, destStride
386 mov eax, dup
387 mov ebp, srcStride
388 push eax
389 myLoopN:
390 movd mm0, [esi]
391 movd mm1, [esi + ebx]
392 punpcklbw mm0, mm2
393 punpcklbw mm1, mm2
394 pmullw mm0, mm1
395 push ecx
396 psrlw mm0, 8
397 mov ecx, 4[esp]
398 packuswb mm0, mm0
399 movd eax, mm0
400 dupLoopN:
401 mov [edi], eax
402 dec ecx
403 lea edi, [edi + edx]
404 jne dupLoopN
405 pop ecx ; get back the loop counter
406 add esi, ebp
407 dec ecx
408 jne myLoopN
409 pop eax
410 pop ebp
411 emms
416 #endif
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())
425 #endif
426 { // unoptimized version
427 if (dup == 1)
429 while (numColors--)
431 dest->sub(*src1, *src2);
432 dest = (CRGBA *) ((uint8 *) dest + destStride);
433 src1 = (CRGBA *) ((uint8 *) src1 + srcStride);
434 src2 = (CRGBA *) ((uint8 *) src2 + srcStride);
437 else
439 if (dup == 4) // optimisation for the 4 case
441 while (numColors--)
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);
455 else
457 while (numColors--)
459 dest->sub(*src1, *src2);
461 uint k = dup - 1;
464 * (CRGBA *) ((uint8 *) dest + destStride) = *dest;
465 dest = (CRGBA *) ((uint8 *) dest + destStride);
467 while (--k);
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)
480 if (dup == 1)
482 __asm
484 push ebp
485 mov edi, dest
486 mov esi, src1
487 mov ebx, src2
488 sub ebx, esi ; offset to source 2
489 mov ecx, numColors
490 mov edx, destStride
491 mov ebp, srcStride
492 sub edi, edx
493 myLoop:
494 movd mm0, [esi]
495 add edi, edx
496 movd mm1, [esi + ebx]
497 psubusb mm0, mm1
498 movd [edi], mm0
499 add esi, ebp
500 dec ecx
501 jne myLoop
502 pop ebp
503 emms
506 else
508 if (dup == 4)
510 __asm
512 push ebp
513 mov edi, dest
514 mov esi, src1
515 mov ebx, src2
516 sub ebx, esi ; offset to source 2
517 mov ecx, numColors
518 mov edx, destStride
519 mov ebp, srcStride
520 myLoop4:
521 movd mm0, [esi]
522 movd mm1, [esi + ebx]
523 psubusb mm0, mm1
524 movd eax, mm0
526 mov [edi], eax
527 mov [edi + edx], eax
528 mov [edi + 2 * edx], eax
529 lea edi, [edi + edx * 2]
530 mov [edi + edx], eax
531 lea edi, [edi + edx * 2]
532 add esi, ebp
534 dec ecx
535 jne myLoop4
536 pop ebp
537 emms
540 else
542 __asm
544 push ebp
545 mov edi, dest
546 mov esi, src1
547 mov ebx, src2
548 sub ebx, esi ; offset to source 2
549 mov ecx, numColors
550 mov edx, destStride
551 mov eax, dup
552 mov ebp, srcStride
553 push eax
554 myLoopN:
555 movd mm0, [esi]
556 movd mm1, [esi + ebx]
557 push ecx
558 psubusb mm0, mm1
559 mov ecx, 4[esp]
560 movd eax, mm0
561 dupLoopN:
562 mov [edi], eax
563 dec ecx
564 lea edi, [edi + edx]
565 jne dupLoopN
566 pop ecx ; get back the loop counter
567 add esi, ebp
568 dec ecx
569 jne myLoopN
570 pop eax
571 pop ebp
572 emms
577 #endif
580 // ***************************************************************************
581 // ***************************************************************************
582 // CBGRA
583 // ***************************************************************************
584 // ***************************************************************************
587 // ***************************************************************************
588 void CBGRA::serial(NLMISC::IStream &f)
590 f.serial (B);
591 f.serial (G);
592 f.serial (R);
593 f.serial (A);
596 // ***************************************************************************
597 void CBGRA::set(uint8 r, uint8 g, uint8 b, uint8 a)
599 R = r;
600 G = g;
601 B = b;
602 A = a;
605 // ***************************************************************************
606 void CBGRA::blendFromui(CBGRA &c0, CBGRA &c1, uint coef) // coef must be in [0,256]
608 sint a1 = coef;
609 sint a2 = 256-a1;
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
619 float r = R / 255.f;
620 float g = G / 255.f;
621 float b = B / 255.f;
623 float maxV = NLMISC::maxof(r, g, b);
624 float minV = NLMISC::minof(r, g, b);
626 // all composants are equals -> achromatique
627 if (minV == maxV)
629 h = 0.f;
630 l = minV;
631 s = 0.f;
632 return true;
635 // get lightness
636 l = 0.5f * (maxV + minV);
638 float diff = maxV - minV;
640 // get saturation
641 s = l > 0.5f ? /*are we in the top of the double-hexcone ? */
642 diff / (2.f - maxV - minV) :
643 diff / (maxV + minV);
645 // get hue
646 if (maxV == r)
648 h = (g - b) / diff;
650 else if (maxV == g)
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
656 else if (maxV == b)
658 h = 4.f + (r - g) / diff;
660 else
662 // this case is to fix a compiler bug
663 h = (g - b) / diff;
665 #else
666 else
668 h = 4.f + (r - g) / diff;
670 #endif
672 h *= 60.f; // scale to [0..360]
674 if (h < 0.f) h += 360.f;
676 return false;
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;
689 if (h < 60.f)
691 return v1 + (v2 - v1) * h / 60.f;
693 else if (h < 180.f)
695 return v2;
697 else if (h < 240.f)
699 return v1 + (v2 - v1) * (240.f - h) / 60.f;
701 else
703 return v1;
708 // ***************************************************************************
709 void CRGBA::buildFromHLS(float h, float l, float s)
711 clamp(l, 0.f, 1.f);
712 clamp(s, 0.f, 1.f);
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
723 float v;
725 v = HLSValue(h + 120.f, v1, v2);
726 clamp(v, 0.f, 1.f);
727 R = (uint8) (255.f * v);
729 v = HLSValue(h, v1, v2);
730 clamp(v, 0.f, 1.f);
731 G = (uint8) (255.f * v);
733 v = HLSValue(h - 120.f, v1, v2);
734 clamp(v, 0.f, 1.f);
735 B = (uint8) (255.f * v);
739 CRGBA CRGBA::stringToRGBA( const char *ptr )
741 if (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)
748 clamp( r, 0, 255 );
749 clamp( g, 0, 255 );
750 clamp( b, 0, 255 );
751 clamp( a, 0, 255 );
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)
759 clamp(r, 0, 255);
760 clamp(g, 0, 255);
761 clamp(b, 0, 255);
762 clamp(a, 0, 255);
764 return CRGBA(r, g, b, a);
768 return NLMISC::CRGBA::White;
771 std::string CRGBA::toString() const
773 std::string s;
774 s = NLMISC::toString( R );
775 s += " ";
776 s += NLMISC::toString( G );
777 s += " ";
778 s += NLMISC::toString( B );
779 s += " ";
780 s += NLMISC::toString( A );
781 return s;
784 bool CRGBA::fromString( const std::string &s )
786 *this = stringToRGBA( s.c_str() );
787 return true;
791 // ***************************************************************************
792 // ***************************************************************************
793 // CRGBAF
794 // ***************************************************************************
795 // ***************************************************************************
798 // ***************************************************************************
799 void CRGBAF::serial(NLMISC::IStream &f)
801 f.serial (R);
802 f.serial (G);
803 f.serial (B);
804 f.serial (A);
806 // ***************************************************************************
807 void CRGBAF::set(float r, float g, float b, float a)
809 R = r;
810 G = g;
811 B = b;
812 A = a;
815 } // NLMISC