ArkWrite.swift 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //
  2. // Copyright 2026 Aarav Ravindra Kharade
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. import ark.sys.libc
  17. public class ArkWrite {
  18. private let graphics: ArkGraphics
  19. public init(graphics: ArkGraphics) {
  20. self.graphics = graphics
  21. }
  22. public func drawText(_ text: String, x: Int, y: Int, size: Int, r: UInt8, g: UInt8, b: UInt8) {
  23. var cursorX = x
  24. var charW = ArkFontRobotoBold.charWidth
  25. var charH = ArkFontRobotoBold.charHeight
  26. var fontData = ArkFontRobotoBold.data
  27. var drawScale = size
  28. if size % 6 == 0 {
  29. charW = ArkFontRobotoBold.charWidth6x
  30. charH = ArkFontRobotoBold.charHeight6x
  31. fontData = ArkFontRobotoBold.data6x
  32. drawScale = size / 6
  33. } else if size % 4 == 0 {
  34. charW = ArkFontRobotoBold.charWidth4x
  35. charH = ArkFontRobotoBold.charHeight4x
  36. fontData = ArkFontRobotoBold.data4x
  37. drawScale = size / 4
  38. } else if size % 3 == 0 {
  39. charW = ArkFontRobotoBold.charWidth3x
  40. charH = ArkFontRobotoBold.charHeight3x
  41. fontData = ArkFontRobotoBold.data3x
  42. drawScale = size / 3
  43. } else if size % 2 == 0 {
  44. charW = ArkFontRobotoBold.charWidth2x
  45. charH = ArkFontRobotoBold.charHeight2x
  46. fontData = ArkFontRobotoBold.data2x
  47. drawScale = size / 2
  48. }
  49. for char in text {
  50. let ascii = char.asciiValue ?? 63 // '?' as fallback
  51. var max_col = -1
  52. var min_col = charW
  53. if ascii >= 32 && ascii <= 126 {
  54. let offset = Int(ascii - 32) * (charW * charH)
  55. // First pass: find bounding box
  56. for row in 0..<charH {
  57. for col in 0..<charW {
  58. let alpha = fontData[offset + row * charW + col]
  59. if alpha > 0 {
  60. if col < min_col { min_col = col }
  61. if col > max_col { max_col = col }
  62. }
  63. }
  64. }
  65. // Second pass: draw
  66. if max_col != -1 {
  67. for row in 0..<charH {
  68. for col in min_col...max_col {
  69. let alpha = fontData[offset + row * charW + col]
  70. if alpha > 0 {
  71. graphics.fillRectRGBA(
  72. x: cursorX + (col - min_col) * drawScale,
  73. y: y + (charH - 1 - row) * drawScale,
  74. w: drawScale,
  75. h: drawScale,
  76. r: r, g: g, b: b, a: alpha
  77. )
  78. }
  79. }
  80. }
  81. }
  82. }
  83. var charActualW = 0
  84. if max_col == -1 && ascii == 32 {
  85. charActualW = charW / 3
  86. } else if max_col != -1 {
  87. charActualW = (max_col - min_col + 1) + (charW / 16) // Padding between chars
  88. } else {
  89. charActualW = charW / 2
  90. }
  91. cursorX += charActualW * drawScale
  92. }
  93. }
  94. public static func measureText(_ text: String, size: Int) -> ArkSize {
  95. var cursorX = 0
  96. var charW = ArkFontRobotoBold.charWidth
  97. var charH = ArkFontRobotoBold.charHeight
  98. var fontData = ArkFontRobotoBold.data
  99. var drawScale = size
  100. if size % 6 == 0 {
  101. charW = ArkFontRobotoBold.charWidth6x
  102. charH = ArkFontRobotoBold.charHeight6x
  103. fontData = ArkFontRobotoBold.data6x
  104. drawScale = size / 6
  105. } else if size % 4 == 0 {
  106. charW = ArkFontRobotoBold.charWidth4x
  107. charH = ArkFontRobotoBold.charHeight4x
  108. fontData = ArkFontRobotoBold.data4x
  109. drawScale = size / 4
  110. } else if size % 3 == 0 {
  111. charW = ArkFontRobotoBold.charWidth3x
  112. charH = ArkFontRobotoBold.charHeight3x
  113. fontData = ArkFontRobotoBold.data3x
  114. drawScale = size / 3
  115. } else if size % 2 == 0 {
  116. charW = ArkFontRobotoBold.charWidth2x
  117. charH = ArkFontRobotoBold.charHeight2x
  118. fontData = ArkFontRobotoBold.data2x
  119. drawScale = size / 2
  120. }
  121. for char in text {
  122. let ascii = char.asciiValue ?? 63 // '?' as fallback
  123. var max_col = -1
  124. var min_col = charW
  125. if ascii >= 32 && ascii <= 126 {
  126. let offset = Int(ascii - 32) * (charW * charH)
  127. for row in 0..<charH {
  128. for col in 0..<charW {
  129. let alpha = fontData[offset + row * charW + col]
  130. if alpha > 0 {
  131. if col < min_col { min_col = col }
  132. if col > max_col { max_col = col }
  133. }
  134. }
  135. }
  136. }
  137. var charActualW = 0
  138. if max_col == -1 && ascii == 32 {
  139. charActualW = charW / 3
  140. } else if max_col != -1 {
  141. charActualW = (max_col - min_col + 1) + (charW / 16)
  142. } else {
  143. charActualW = charW / 2
  144. }
  145. cursorX += charActualW * drawScale
  146. }
  147. return ArkSize(w: cursorX, h: charH * drawScale)
  148. }
  149. }