home *** CD-ROM | disk | FTP | other *** search
- ; map16_accurate.s
- ; MACHINE: RISC OS
- ; LANGUAGE: OBJASM assembler
- ; AUTHOR: Cy Booker, cy@cheepnis.demon.co.uk
- ; LICENSE: FreeWare, Copyright (c) Cy Booker 1995
- ; PURPOSE: Given an arbitary 48-bit colour, what is the closest 16-bit colour?
-
- GET OS:Hdr.os
-
- ;
- ; in middle we have |intensity-difference| <-- 0xffff * 2 / 0x1f
- ; so |i|^2 < 0x0110c631
- ; and so |d|^2 < 0x03325293
- ;
- ; the weights we want are:
- ; Red * 0.212671 *256 = 54 (0x36) *179 = 38 0x26
- ; Green * 0.715160 *256 = 183 (0xb7) *179 = 128 0x80
- ; Blue * 0.072169 *256 = 19 (0x13) *179 = 13 0x0d
- ;
- ; note we will use the *179 because it makes the inline multiplies very quick
- ; note we divide by 4 so that total difference fits in 32 (unsigned) bits
- ; ie (0x03325293 * 179 / 4) < 2^32
- ;
-
- MACRO
- Dump
- [ {FALSE}
- STMFD sp!, {a1-v6, ip, lr}
- STMFD sp!, {d}
- MOV a4, delta_grn
- MOV a3, delta_blu
- MOV a2, delta_red
- ADR a1, __format
- IMPORT _printf
- ; BL _printf
- B %FT1
- _format = "delta= {%8x, %8x, %8x}, dist= %8x\n", 0
- ALIGN
- 1
- ADD sp, sp, #4
- LDMFD sp!, {a1-v6, ip, lr}
- ]
- MEND
-
-
- EXPORT map_scaled_rgb_to_16bpp_colour_accurate
-
- AREA |ARM$$code|, CODE, READONLY
-
- ROUT
-
- ;
- ; In R0 -> structure, or NULL
- ; R1 = red nominally [0, 0xffff], but clipped as necessary
- ; R2 = green nominally [0, 0xffff], but clipped as necessary
- ; R3 = blue nominally [0, 0xffff], but clipped as necessary
- ; Out R0 = 16 bit colour number (%0bbb bbgg gggr rrrr)
- ; structure[0] = error in approximating red intensity
- ; structure[1] = error in approximating green intensity
- ; structure[2] = error in approximating blue intensity
- ;
-
- ROUT
-
- str RN a1
- orig_red RN a2
- orig_grn RN a3
- orig_blu RN a4 ; implicit
- delta_red RN v1 ;\;
- delta_grn RN v2 ; \;
- delta_blu RN v3 ;-->
- scaled_red RN v4 ;\;
- scaled_grn RN v5 ; \;
- scaled_blu RN v6 ;-->
- t RN ip
- delta RN str
- d RN scaled_red
- dmin RN scaled_blu
-
-
- ^ 0, sp
- L_str # 4 ; all structure offsets are implicit!
- L_best_delta # 4 * 3
- L_scaled_red # 4
- L_scaled_grn # 0 ; this is in a register!
- L_scaled_blu # 4
- L_distance_red # 4 ; need to remember this
- sizeof_L * :INDEX: {VAR}
-
-
- map_scaled_rgb_to_16bpp_colour_accurate
-
-
- STMFD sp!, {v1-v6, lr}
- STR str, [sp, #-sizeof_L]! ; store and reserve stack space
- MOV lr, #0xff00
- ORR lr, lr, #0xff
- CMP orig_red, #0x10000 ; ensure in range [0, 0xffff]
- MOVHS orig_red, #0
- MOVGE orig_red, lr
- CMP orig_grn, #0x10000
- MOVHS orig_grn, #0
- MOVGE orig_grn, lr
- CMP orig_blu, #0x10000
- MOVHS orig_blu, #0
- MOVGE orig_blu, lr
-
- AND t, orig_red, #&f800 ; t = simple approximation of red * 2 ^ (16 - 5)
- ORR t, t, t, LSR #5
- ORR t, t, t, LSR #10
- ORR t, t, t, LSR #15 ; t ~= t * 0xffff / 0x1f
- STR t, L_scaled_red
-
- AND t, orig_grn, #&f800
- ORR t, t, t, LSR #5
- ORR t, t, t, LSR #10
- ORR scaled_grn, t, t, LSR #15
-
- AND t, orig_blu, #&f800
- ORR t, t, t, LSR #5
- ORR t, t, t, LSR #10
- ORR t, t, t, LSR #15
- STR t, L_scaled_blu
-
- MOV delta, #&0800
- ORR delta, delta, #&0042 ; delta= 0xffff / 0x1f
- MOV dmin, #&ffffffff
-
- MOV delta_red, delta
- red_loop
- LDR t, L_scaled_red
- ADD t, t, delta_red
- CMP t, #0x10000
- BHS skip_red_loop ; ensure in range [0, 0xffff]
- SUBS d, t, orig_red
- RSBMI d, d, #0 ; makes multiply faster
- MULNE t, d, d
- ; scale for red...
- ADDNE d, t, t, LSR #1 ; |r|^2 * 0.072169 * 179 / 4 = |r|^2 * 0x06
- ADDNE d, d, t, LSL #3 ; |r|^2 * 0.072169 * 179 / 4 = |r|^2 * 0x26
- STR d, L_distance_red
-
- MOV delta_blu, delta
- blu_loop
- LDR t, L_scaled_blu
- ADD t, t, delta_blu
- CMP t, #0x10000
- BHS skip_blu_loop ; ensure in range [0, 0xffff]
-
- SUBS t, t, orig_blu
- RSBMI t, t, #0
- MULNE lr, t, t
- ; scale for blue
- ADDNE d, d, lr ; (|b|^2 / 4) * 0x04
- ADDNE d, d, lr, LSR #2 ; (|b|^2 / 4) * 0x05
- ADDNE d, d, lr, LSL #1 ; (|b|^2 / 4) * 0x0d
-
- MOV delta_grn, delta
- grn_loop
- ADD t, scaled_grn, delta_grn
- CMP t, #0x10000
- BHS skip_grn_loop ; ensure in range [0, 0xffff]
- SUBS t, t, orig_grn
- RSBMI t, t, #0 ; speeds up multiplication
- MUL lr, t, t
- ; scale for green ...
- ADD d, d, lr, LSL #5 ; |g|^2 * 0.715160 * 179 / 4 = |g|^2 * 0x80
- Dump
- CMP d, dmin
- MOVLO dmin, d
- STMLOIB sp, {delta_red, delta_grn, delta_blu} ; note the best so far
- SUB d, d, lr, LSL #5 ; restore distance accumulator
- skip_grn_loop
- SUBS delta_grn, delta_grn, delta
- BLS grn_loop ; loop +1, 0, -1
-
- LDR d, L_distance_red ; restore distance accumulator
- skip_blu_loop
- SUBS delta_blu, delta_blu, delta
- BLS blu_loop ; loop +1, 0, -1
-
- skip_red_loop
- SUBS delta_red, delta_red, delta
- BLS red_loop ; loop +1, 0, -1
-
- ; the final lr is just to clear the stack
- LDMIA sp!, {str, delta_red, delta_grn, delta_blu, scaled_red, scaled_blu, lr}
- ADD scaled_red, scaled_red, delta_red
- ADD scaled_grn, scaled_grn, delta_grn
- ADD scaled_blu, scaled_blu, delta_blu
- TEQ str, #0
- SUBNE orig_red, orig_red, scaled_red
- SUBNE orig_grn, orig_grn, scaled_grn
- SUBNE orig_blu, orig_blu, scaled_blu
- STMNEIA str, {orig_red, orig_grn, orig_blu} ; store `error'
-
- MOV t, scaled_red, LSR #16 - 5
- MOV lr, scaled_grn, LSR #16 - 5
- ORR t, t, lr, LSL #5
- MOV lr, scaled_blu, LSR #16 - 5
- ORR a1, t, lr, LSL #10 ; construct 16-bit colour number
-
- LDMFD sp!, {v1-v6, pc}^
-
- END
-