-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathQDSpy_stim_support.py
120 lines (97 loc) · 3.72 KB
/
QDSpy_stim_support.py
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
QDSpy module - support functions for stimulus generation and compilation
'rotateTranslate()'
Rotate the coordinates by the given angle
'scaleRGB()'
'scaleRGBShader()'
Scale color as RGBA depending on bit depth and color mode
'getHashStr()'
'getHashStrForFile()'
Get hashes for strings or files
'Log'
Class that allows program-wide flexible logging. Only one instance that
is defined in this module. Writes log messages to stdout and/or sends
messages via a pipe to the GUI process.
Copyright (c) 2013-2024 Thomas Euler
All rights reserved.
2021-10-15 - Account for LINUX console text coloring
2024-08-13 - Move file-related functions to own module
"""
# ---------------------------------------------------------------------
__author__ = "[email protected]"
import numpy as np
import QDSpy_stim as stm
# ---------------------------------------------------------------------
def rotateTranslate(_coords, _rot_deg, _posxy):
# Rotate the coordinates in the list ([x1,y1,x2,y2, ...]) by the
# given angle
#
coords = []
a_rad = np.radians(_rot_deg)
for i in range(0, len(_coords), 2):
x = _coords[i] * np.cos(a_rad) + _coords[i + 1] * np.sin(a_rad) + _posxy[0]
y = -_coords[i] * np.sin(a_rad) + _coords[i + 1] * np.cos(a_rad) + _posxy[1]
coords += [x, y]
return coords
# ---------------------------------------------------------------------
def toInt(_coords):
# Convert the coordinates in the list to integers
#
coords = []
for v in _coords:
coords.append(int(v))
return coords
# ---------------------------------------------------------------------
def completeRGBList(_RGBs):
# Complete each RGBx2 tuple if incomplete in the given list
#
return [tuple(list(rgb) + [0] * (stm.RGB_MAX - len(rgb))) for rgb in _RGBs]
def completeRGBAList(_RGBAs):
# Complete each RGBAx2 tuple if incomplete in the given list
#
res = []
for obj in _RGBAs:
res.append([rgba + (0,) * (stm.RGBA_MAX - len(rgba)) for rgba in obj])
return res
# ---------------------------------------------------------------------
def scaleRGB(_Stim, _inRGBA):
# Scale color (RGBA) depending on bit depth and color mode (format)
#
if _Stim.colorMode >= stm.ColorMode.LC_first:
# One of the lightcrafter specific modes ...
#
if _Stim.colorMode == stm.ColorMode.LC_G9B9:
RGBA = np.clip(_inRGBA, 0, 255)
g = 2 ** int(RGBA[1] / 255.0 * 8) - 1
b = 2 ** int(RGBA[2] / 255.0 * 8) - 1
return 0, g, b, int(RGBA[3])
else:
return 255, 255, 255, 255
else:
# One of the "normal" modes ...
#
if _Stim.colorMode == stm.ColorMode.range0_255:
RGBA = np.clip(_inRGBA, 0, 255)
dv = 255.0
elif _Stim.colorMode == stm.ColorMode.range0_1:
RGBA = np.clip(_inRGBA, 0, 1)
dv = 1.0
r = int(RGBA[0] / dv * (2 ** _Stim.bitDepth[0] - 1)) << _Stim.bitShift[0]
g = int(RGBA[1] / dv * (2 ** _Stim.bitDepth[1] - 1)) << _Stim.bitShift[1]
b = int(RGBA[2] / dv * (2 ** _Stim.bitDepth[2] - 1)) << _Stim.bitShift[2]
RGB = tuple(np.clip((r, g, b), 0, 255))
return RGB + (int(RGBA[3]),)
# ---------------------------------------------------------------------
def scaleRGBShader(_Stim, _inRGBA):
# Scale color (RGBA) depending on bit depth and color mode (format)
# into shader compatible values (0...1)
#
r = _inRGBA[0] / 255.0
g = _inRGBA[1] / 255.0
b = _inRGBA[2] / 255.0
a = _inRGBA[3] / 255.0
RGBA = tuple(np.clip((r, g, b, a), 0.0, 1.0))
return RGBA
# ---------------------------------------------------------------------