1 module rpui.render.transforms; 2 3 import std.math; 4 5 import gapi.vec; 6 import gapi.font; 7 import gapi.text; 8 import gapi.transform; 9 import gapi.texture; 10 11 import rpui.events; 12 import rpui.widget; 13 import rpui.render.components; 14 import rpui.alignment; 15 16 interface TransformsSystem { 17 void onProgress(in ProgressEvent event); 18 } 19 20 private vec2 toScreenPosition(in float windowHeight, in vec2 position, in float height) { 21 return vec2(floor(position.x), floor(windowHeight - height - position.y)); 22 } 23 24 QuadTransforms updateQuadTransforms( 25 in CameraView cameraView, 26 in vec2 position, 27 in vec2 size 28 ) { 29 QuadTransforms transforms; 30 31 with (transforms) { 32 transform.position = toScreenPosition(cameraView.viewportHeight, position, size.y); 33 transform.scaling = size; 34 modelMatrix = create2DModelMatrix(transform); 35 mvpMatrix = cameraView.mvpMatrix * modelMatrix; 36 } 37 38 return transforms; 39 } 40 41 LinesTransforms updateLinesTransforms(in CameraView cameraView, in vec2 position) { 42 LinesTransforms transforms; 43 44 with (transforms) { 45 const screenPosition = toScreenPosition(cameraView.viewportHeight, position, 0); 46 modelMatrix = create2DModelMatrixPosition(screenPosition); 47 mvpMatrix = cameraView.mvpMatrix * modelMatrix; 48 } 49 50 return transforms; 51 } 52 53 BlockTransforms updateBlockTransforms( 54 in float[ChainPart][BlockRow] partWidths, 55 in float[BlockRow] partHeights, 56 in CameraView cameraView, 57 in vec2 position, 58 in vec2 size, 59 ) { 60 BlockTransforms transforms; 61 62 const topSize = vec2(size.x, partHeights[BlockRow.top]); 63 const bottomSize = vec2(size.x, partHeights[BlockRow.bottom]); 64 const middleSize = vec2(size.x, size.y - topSize.y - bottomSize.y); 65 66 const topPosition = position; 67 const middlePosition = topPosition + vec2(0, topSize.y); 68 const bottomPosition = middlePosition + vec2(0, middleSize.y); 69 70 transforms.topChain = updateHorizontalChainTransforms( 71 partWidths[BlockRow.top], 72 cameraView, 73 topPosition, 74 topSize 75 ); 76 77 transforms.middleChain = updateHorizontalChainTransforms( 78 partWidths[BlockRow.middle], 79 cameraView, 80 middlePosition, 81 middleSize 82 ); 83 84 transforms.bottomChain = updateHorizontalChainTransforms( 85 partWidths[BlockRow.bottom], 86 cameraView, 87 bottomPosition, 88 bottomSize 89 ); 90 91 return transforms; 92 } 93 94 HorizontalChainTransforms updateHorizontalChainTransforms( 95 in float[ChainPart] partWidths, 96 in CameraView cameraView, 97 in vec2 position, 98 in vec2 size, 99 in Widget.PartDraws partDraws = Widget.partDraws.all 100 ) { 101 HorizontalChainTransforms transforms; 102 103 auto leftSize = vec2(partWidths[ChainPart.left], size.y); 104 auto rightSize = vec2(partWidths[ChainPart.right], size.y); 105 auto centerSize = vec2(size.x - leftSize.x - rightSize.x, size.y); 106 107 auto leftPos = position; 108 auto centerPos = leftPos + vec2(leftSize.x, 0); 109 auto rightPos = centerPos + vec2(centerSize.x, 0); 110 111 switch (partDraws) { 112 case Widget.PartDraws.left: 113 centerSize.x += rightSize.x; 114 break; 115 116 case Widget.PartDraws.center: 117 centerPos = position; 118 centerSize = size; 119 break; 120 121 case Widget.PartDraws.right: 122 centerPos = leftPos; 123 centerSize.x += leftSize.x; 124 break; 125 126 default: 127 // Nothing 128 } 129 130 with (transforms) { 131 quadTransforms[ChainPart.left] = updateQuadTransforms(cameraView, leftPos, leftSize); 132 quadTransforms[ChainPart.center] = updateQuadTransforms(cameraView, centerPos, centerSize); 133 quadTransforms[ChainPart.right] = updateQuadTransforms(cameraView, rightPos, rightSize); 134 } 135 136 return transforms; 137 } 138 139 HorizontalChainTransforms updateVerticalChainTransforms( 140 in float[ChainPart] partWidths, 141 in CameraView cameraView, 142 in vec2 position, 143 in vec2 size 144 ) { 145 HorizontalChainTransforms transforms; 146 147 const topSize = vec2(size.x, partWidths[ChainPart.top]); 148 const bottomSize = vec2(size.x, partWidths[ChainPart.bottom]); 149 const middleSize = vec2(size.x, size.y - topSize.y - bottomSize.y); 150 151 const topPos = position; 152 const middlePos = topPos + vec2(0, topSize.y); 153 const bottomPos = middlePos + vec2(0, middleSize.y); 154 155 with (transforms) { 156 quadTransforms[ChainPart.top] = updateQuadTransforms(cameraView, topPos, topSize); 157 quadTransforms[ChainPart.middle] = updateQuadTransforms(cameraView, middlePos, middleSize); 158 quadTransforms[ChainPart.bottom] = updateQuadTransforms(cameraView, bottomPos, bottomSize); 159 } 160 161 return transforms; 162 } 163 164 UiTextTransforms updateUiTextTransforms( 165 UiTextRender* uiText, 166 Font* font, 167 in UiTextTransforms oldTransforms, 168 in UiTextAttributes attrs, 169 in CameraView cameraView, 170 in vec2 position, 171 in vec2 size = vec2(0, 0) 172 ) { 173 UiTextTransforms measure; 174 175 if (oldTransforms.cachedString != attrs.caption) { 176 UpdateTextInput updateTextInput = { 177 textSize: attrs.fontSize, 178 font: font, 179 text: attrs.caption 180 }; 181 182 const textUpdateResult = updateTextureText(&uiText.text, updateTextInput); 183 184 uiText.texture = textUpdateResult.texture; 185 measure.size = textUpdateResult.surfaceSize; 186 } else { 187 measure.size = oldTransforms.size; 188 } 189 190 measure.cachedString = attrs.caption; 191 vec2 textPosition = position + attrs.offset; 192 193 if (size != vec2(0, 0)) { 194 textPosition.x += alignBox(attrs.textAlign, measure.size.x, size.x); 195 textPosition.y += verticalAlignBox(attrs.textVerticalAlign, measure.size.y, size.y); 196 } 197 198 const Transform2D textTransform = { 199 position: toScreenPosition(cameraView.viewportHeight, textPosition, measure.size.y), 200 scaling: measure.size 201 }; 202 203 measure.mvpMatrix = cameraView.mvpMatrix * create2DModelMatrix(textTransform); 204 measure.relativePosition = textPosition - position; 205 206 return measure; 207 } 208 209 vec2 getUiTextBounds( 210 UiTextRender* uiText, 211 Font* font, 212 in UiTextAttributes attrs 213 ) { 214 UpdateTextInput updateTextInput = { 215 textSize: attrs.fontSize, 216 font: font, 217 text: attrs.caption 218 }; 219 220 return getTextBounds(&uiText.text, updateTextInput); 221 }