Москвич-408 — элегантность, ставшая классикой

Тема в разделе "Vulkan", создана пользователем ml64, 25 июл 2026.

  1. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.025
    Если называть ЯВУ все что не является ассемблером(например си): на ЯВУ есть свой кайф при программировании.
    Например если твой код не зависит от внешних библиотек/фреймворков это тоже кайф.
     
  2. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    А вот тут Intel был ни при чём. Это был типичный ассемблерный ночной баг.
    Нашёл, исправил.

    Мне одному не дают спать Вулкан и ассемблер по ночам?

    RR_07.jpeg
     

    Вложения:

    Последнее редактирование: 12 авг 2026
    Mikl___ и Application нравится это.
  3. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    541
    Нет я тоже по всем ночам не сплю - всё жду когда вы мне, под мой музейный экспонат процессора, код на MASM64 - для OpenGL напишите. :)
     
  4. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    Раз обещал - нехорошо заставлять ждать.
    Вообще я хотел сначала закончить парсер obj -> VBO, а потом перенести его в OpenGL-рамку, но если Вас терзает бессонница, то придётся отвлечься
     
  5. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    Здесь наши интересы совпадают: мой движок OpenGL основан на технологиях прошлого века (OpenGL 1.0).
    Работать с реальными 3D-моделями он просто не способен. Поэтому мне нужно прикрутить к нему парсер VAO/VBO/EBO.
    Если при этом он кому-то будет полезен, то я только буду рад.
    Vulkan - штука нестабильная и требует наличия библиотеки. OpenGL под Windows запускается из коробки.
    У самурая нет цели, есть только путь. Но я иду в сторону своего IFC-ридера, а возможно, и редактора.
    Мы живём в интересное время.
    Сейчас я один могу делать столько же, сколько 30 лет назад делал весь Autodesk или Graphisoft (в плане разработки, не маркетинга).
    Поэтому мне не жалко написать один модуль, чтобы человеку стало весело.
    Я не гонюсь за авторским правом, потому что всё это придумано не мной и давно написано, я учусь сам и показываю другим людям.
     
    GRAFik и Mikl___ нравится это.
  6. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    Альтернативное времяпрепровождение - это прикольные видосики в телефоне.
    В лучшем случае просто тупые, в худшем - пропагандистские.
    Я выбрал другой путь. Так узнаю много нового (технологически нового) и держу мозг в тонусе.
    И я не знаю, где пригодятся мои знания в будущем.
    Уже сейчас я держу в руках связку WinAPI-Vulkan-GLSL, причём на чистом ассемблере, без третьих библиотек.
    Считаю матрицы преобразований с помощью AVX и FMA.
    В реальной жизни это мне никогда не пригодится. Почти наверное. Никто даже не знает, что я это умею.
    А что если я по приколу напишу свой мини-Revit, который будет соответствовать ГОСТам?
    Тупо чтобы потроллить Нанософт и Аскон?

    Задача по линии VK и OpenGL сейчас единая - мне нужен парсер obj -> VBO, причём не просто какой-нибудь, а хороший, годный - построенный на векторных инструкциях.
    Когда будет парсер, будет и визуализация
     
    Последнее редактирование: 13 авг 2026
    Mikl___ нравится это.
  7. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    4.281
    ml64,
    мне кажется, что на картинке девочка-подросток с большой грудью или у «Москвича» размер «Чайки»? :yes3:
    размеры«Чайка»«Москвич 408»
    длина5600 мм4090 мм
    ширина2000 мм1550 мм
    высота1620 мм1480 мм
    колёсная база3250 мм2400 мм
     

    Вложения:

    • 7895308s-960.jpg
      7895308s-960.jpg
      Размер файла:
      687,4 КБ
      Просмотров:
      147
    Последнее редактирование: 13 авг 2026
    ml64 нравится это.
  8. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    Исправил
    RR_07a.jpeg
     
    Mikl___ и Application нравится это.
  9. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    541
    А мне дед старые фотографии показывал, когда были в моде "инвалидки", как в старой комедии "самогонщики". Вот такую бы подкрасить, подсветить и с такой девушкой сфотографировать. :)
     
  10. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    Самогонщики сами бегали. Причём на лыжах, сквозь берёзу. Мотоколяска была в "Операции "Ы"
     
  11. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    541
    Точно, именно мотоколяска. У вас нет такой в вашей кодовой базе ? Тогда сразу оформляем спецзаказ, с полной предоплатой. Девушки только могут подвести. Они на такой позор могут не подписаться - ни за какие деньги. :)
     
  12. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    4.281
    GRAFik,
    «Операция Ы» — мотоколяска СМЗ С-3А
    «Кавказская пленница» — немецкий Adler Triumpf Junior 1937 года
     
  13. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.025
    Может такое проще на python делать? В асм передавать сконвертированные файлы.
     
  14. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    Однозначно - да. На ЯВУ - проще.
    Но cmd = parts(i) - это действия, которые повторяются каждый байт (при каждом проходе):
    1) вычисление адреса parts - это два лишних обращения к памяти:
    lea rax,parts
    add parts,i
    2) весь перебор if cmd == 'v' и др. - это побайтовый опрос.
    Это долго.
    Для "Москвича" это не критично. Но мои объекты - это здания из огромного количества полигонов.
    Здесь нужны векторные возможности процессора, например, VPCMPISTRI
    Эта инструкция поможет определить, есть ли в строке нужные токены, а дальше можно уже по байтам разбирать, как с ними работать.

    Над чем я сейчас работаю:
    Сколько памяти выделить для буфера вершин?
    Можно взять с запасом, но это только для "Москвича" годится.
    Значит, надо считать. Как считать?
    Ищем строки, которые начинаются с "v". Но это могут быть и "v" с пробелом, и "v" с Tab, и "vn", и "vt".
    Как мы ищем? С помощью CMPSB? Нет, конечно.
    CMPSD? Но она сравнивает последовательность байт с последовательностью байт
    Берём VPCMPISTRI. Она сравнивает независимые 16 байт образца с последовательными 16 байтами памяти и ставит флаги, если находит первый совпавший байт.
    Очень удобно искать конец строки, если токен уже отработан или не нужен.

    Это база, а дальше - на любителя.
    Можно первым проходом заменить весь Tab на пробелы, можно удалить ведущие пробелы в начале строк,
    можно этого не делать, а просто посчитать количество токенов каждого типа и под них выделить нужное количество буферной памяти,
    можно идти в лоб и писать сразу в буфер VBO,
    но тогда получится монолитный объект, и я не смогу, например, открывать капот и двери "Москвича"

    Так что ЯВУ - это хорошо, но это не наш метод.
    Если бы я хотел просто и быстро крутить модель, я открыл бы её в SketchUp
    А мне интересен сам механизм.
     
    Последнее редактирование: 13 авг 2026
  15. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    195
    Думал я думал - что это? Даже VPCMPISTRI посмотрел в сети - ничего не понял.
    Код (ASM):
    1. Mov eDi, Начальный Адрес
    2. Mov eCx, Сколько
    3. ClD / StD ; - направление
    4. Mov Al, 'v' ; что
    5. RepNE ScasB
    6. MovZx  eBx, Byte ptr [eDi]
    7. BT  [BitTab], eBx  ; по битмап допустимых после 'v' байт
    8. ??
     
  16. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    SCASB обращается к памяти каждый раз. Точнее, сейчас уже Intel это как-то кэширует (именно "как-то", т.к. это делает их тайный микрокод).

    Рассмотрим конкретный пример. Пример возьмём попроще - из широко известного в узких кругах пакета tinyobj_loader - см. вложение.
    Мне нужно узнать, сколько выделять памяти под буфер, т.е. сколько в исходном .obj-файле вершин, нормалей, полигонов, объектов, групп и прочих элементов.
    Моя задача - не найти символ "v" в строке, а подсчитать количество токенов "v", "vn", "vt", "o", "g" и т.д. в двух файлах: "геометрия.obj" и "материалы.mat".
    Причём даже встроенный в 3ds Max конвертер сохраняет данные, мягко говоря, не совсем удобно.
    Он может добавить Tab в начало строки, а может не добавить, он может задать вершины, а только потом объявить токен "o" ("объект"), так, что непонятно, к какому объекту эти вершины потом отнести.

    Мой алгоритм:
    Я беру первый значащий символ в строке, сравниваю его с пробелом, табом, LF, CR, EoF, # (комментарий в формате obj) - для каждого случая свой обработчик.
    Всё. Я определил, что символ значащий, дальше его обрабатываю.
    Если "o", то увеличиваю счётчик объектов, если "v", то увеличиваю счётчик вершин и т.д.

    А теперь представьте, что я для этого использую SCASB.
    1) Мне надо для каждого токена запускать свой цикл сканирования (а если файл 20 мегабайт? Это не редкость для современной графики)
    2) а если v - это не токен, а часть имени объекта, например, o vase - объект "ваза"?

    Сейчас я просто ищу начало строки, беру в ней первый значащий символ и сравниваю байт (или слово) по адресу rcx с ASCII-кодом первого символа токена:
    Код (ASM):
    1. countObjEntities proc
    2. LOCAL pCurrentPosition:QWORD,hHeap:QWORD
    3. LOCAL nObjectIndex:DWORD,nMaterialIndex:DWORD
    4.  
    5. PROLOG 100h
    6.  
    7. ;Set the Local Pointer
    8. mov rcx,gpObjDataStart
    9. mov pCurrentPosition,rcx
    10.  
    11. ;Initialize Counters
    12. mov gnTotalObjects,0
    13. mov gnTotalGroups,0
    14. mov gnTotalSubGroups,0
    15. mov gnTotalVertices,0
    16. mov gnTotalNormals,0
    17. mov gnTotalFaces,0
    18. mov gnTotalMtlLibs,0
    19. mov gnTotalIndices,0
    20.  
    21. ;Initialize Indices
    22. mov nObjectIndex,0
    23.  
    24. lbl_NextLine:
    25.  
    26. mov rcx,pCurrentPosition
    27. cmp rcx,gpObjDataEnd
    28. jge lbl_EndOfFile
    29.  
    30. ;Check for consistency
    31. mov al,byte ptr[rcx]
    32. cmp al,0 ;EOF
    33. je  lbl_EndOfFile
    34. cmp al,9 ;Tab
    35. je  lbl_SkipByte
    36. cmp al,0Ah ;CR
    37. je  lbl_SkipByte
    38. cmp al,0Dh ;LF
    39. je  lbl_SkipByte
    40. cmp al,20h ;Space
    41. je  lbl_SkipByte
    42. cmp al,23h ;# OBJ Format Comment
    43. je  lbl_SkipByte
    44.  
    45. ;Token detection. Arranged by Probability
    46. ;mov rcx,pCurrentPosition
    47. cmp byte ptr[rcx],76h ;"v"
    48. je lbl_TokenStartsWithV
    49. cmp byte ptr[rcx],66h ;"f"
    50. je lbl_TokenFace
    51. cmp dword ptr[rcx],6D657375h ;"usem" in reverse order - part of "usemtl"
    52. je lbl_TokenUseMtl
    53. cmp byte ptr[rcx],6Fh ;"o"
    54. je lbl_TokenObject
    55. cmp byte ptr[rcx],67h ;"g"
    56. je lbl_TokenGroup
    57. cmp dword ptr[rcx],6C6C746Dh; "mtll" in reverse order - part of "mtllib"
    58. je lbl_TokenMtlLib
    59. jmp lbl_SkipByte
    60.  
    61. ;Count object name: o name
    62. lbl_TokenObject:
    63. add pCurrentPosition,2 ;skip "o "
    64. inc gnTotalObjects
    65. jmp lbl_SkipByte
    66.  
    67. ;Count object name: g name
    68. lbl_TokenGroup:
    69. add pCurrentPosition,2 ;skip "g "
    70. inc gnTotalGroups
    71. jmp lbl_SkipByte
    72.  
    73. ;Count material: "usemtl"
    74. lbl_TokenUseMtl:
    75. add pCurrentPosition,7 ;skip "usemtl "
    76. inc gnTotalSubGroups
    77. jmp lbl_SkipByte
    78.  
    79. ;Branch V
    80. lbl_TokenStartsWithV:
    81. inc pCurrentPosition
    82. cmp byte ptr[rcx],6Eh ;"n"
    83. je lbl_TokenNormal
    84. cmp byte ptr[rcx],74h ;"t"
    85. je lbl_TokenTextureCoordinate
    86. ;jmp lbl_TokenVertex ;By default
    87.  
    88. ;Count vertex: v x y z
    89. lbl_TokenVertex:
    90. inc pCurrentPosition ;skip "v "
    91. inc gnTotalVertices
    92. jmp lbl_SkipByte
    93.  
    94. ;Count normal: vn x y z
    95. lbl_TokenNormal:
    96. add pCurrentPosition,2 ;skip "vn "
    97. inc gnTotalNormals
    98. jmp lbl_SkipByte
    99.  
    100. ;Count texture: vt u v w
    101. lbl_TokenTextureCoordinate:
    102. add pCurrentPosition,2 ;skip "vt "
    103. inc gnTotalTextureCoords
    104. jmp lbl_SkipByte
    105.  
    106. ;Count face: f v/vt/vn v/vt/vn v/vt/vn
    107. lbl_TokenFace:
    108. inc pCurrentPosition ;skip "f "
    109. inc gnTotalFaces
    110. jmp lbl_SkipByte
    111.  
    112. ;Count material: "mtllib"
    113. lbl_TokenMtlLib:
    114. add pCurrentPosition,7 ;skip "mtllib "
    115. inc gnTotalMtlLibs
    116. jmp lbl_SkipByte
    117.  
    118. lbl_SkipByte:
    119. mov rcx,pCurrentPosition
    120. cmp rcx,gpObjDataEnd
    121. jge lbl_EndOfFile
    122. mov al,byte ptr[rcx]
    123. cmp al,0 ;EOF
    124. je lbl_EndOfFile
    125. cmp al,0Ah ;LF
    126. je lbl_SkipLF
    127. cmp al,0Dh ;CR
    128. je lbl_SkipCR
    129. inc pCurrentPosition
    130. jmp lbl_SkipByte
    131.  
    132. lbl_SkipCR:
    133. inc pCurrentPosition
    134. mov rcx,pCurrentPosition
    135. cmp byte ptr[rcx],0Ah ;LF
    136. je lbl_SkipLF
    137. jmp lbl_NextLine
    138.  
    139. lbl_SkipLF:
    140. inc pCurrentPosition
    141. jmp lbl_NextLine
    142.  
    143. lbl_EndOfFile:
    144. cmp gnTotalObjects,0
    145. jne @f
    146. LOG_TEXT szErrNoObjects
    147. @@:
    148. cmp gnTotalGroups,0
    149. jne @f
    150. LOG_TEXT szErrNoGroups
    151. @@:
    152. cmp gnTotalSubGroups,0
    153. jne @f
    154. LOG_TEXT szErrNoSubGroups
    155. @@:
    156. cmp gnTotalMtlLibs,0
    157. jne @f
    158. LOG_TEXT szErrNoMtlLibs
    159. @@:
    160. cmp gnTotalVertices,0
    161. jne @f
    162. LOG_TEXT szErrNoVertices
    163. @@:
    164. cmp gnTotalNormals,0
    165. jne @f
    166. LOG_TEXT szErrNoNormals
    167. @@:
    168. cmp gnTotalTextureCoords,0
    169. jne @f
    170. LOG_TEXT szErrNoTextureCoords
    171. @@:
    172. cmp gnTotalFaces,0
    173. jne @f
    174. LOG_TEXT szErrNoFaces
    175. @@:
    176.  
    177. ;Success
    178. mov rax,1
    179. jmp lbl_End
    180.  
    181. lbl_WinError:
    182. call SpellWinError
    183. xor rax,rax
    184. ;jmp lbl_End
    185.  
    186. lbl_End:
    187. EPILOG
    188. countObjEntities endp

    Но это неудобно тем, что я для чтения каждого байта обращаюсь к памяти, гоняю этот несчастный байт по всем шинам и контроллерам.
    SSE предлагает хорошее решение - VPCMPISTRI:
    Я создаю в памяти шаблон поиска - 4, 8 или 16 байт для интересующих меня символов, т.е.
    для поиска начала строки и пропуска пустышек это 10h, 13h, 20h, 9,
    для обработки токенов это ASCII-коды o, g, v, m (первые буквы токенов).
    А дальше - дело техники: xmm0 = шаблон поиска, xmm1 или адрес в памяти - сканируемый участок, imm = маска (ANSI или Unicode и другие настройки).
    Как только VPCMPISTRI встречает в заданном диапазоне любой символ из шаблона, она возвращает в RCX смещение этого символа и устанавливает CF.
    Кстати, если она встречает в заданном диапазоне 0, то устанавливает ZF, что очень важно, т.к. можно проскочить EoF.

    Вот над этим я и работаю:
    массово сканирую в поисках 10h, 13h, 20h, 9, а дальше точечно обрабатываю значимые данные.

    Надеюсь, понятно разложил.
     

    Вложения:

    • cornell_box.zip
      Размер файла:
      797 байт
      Просмотров:
      79
    Последнее редактирование: 14 авг 2026
    R81... и Mikl___ нравится это.
  17. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    195
    Да... Команда нужная!
    т.е. поменять Mov Al, 'v' на Mov Al, 10 (после конца предыдущей - начало следующей).

    Непонятно почему, несмотря на
    Вы приводите массивные примеры "Case"- программирования "If"-ами?
    Вместо:
    Код (ASM):
    1.   Mov  eSi, Что разобрать
    2.   Mov  eCx, Сколько максимально -
    3. ; Т.Е. длина файла eCx и ([eSi+eCx]=0=EoF) должен находиться
    4. ; "вне" файла и рассмотрение его избыточно !
    5.   ClD  ; / StD - направление
    6.   xOr  eAx, eAx
    7.   LEA  eBx, [BitMap1]
    8.   LEA  eDx, [CallTab1]  ; или [JmpTab1]
    9. _1:
    10.   LodsB  ; например
    11.   BT  [eBx], eAx  ;;
    12.   JnC  _2  ; возможно ускоряет, если мало токенов в обработке
    13.   Call  [eDx + eAx * 4]  ; если надо почитабельнее
    14. ;  Jmp  [eDx + eAx * 4]  ; как в вашем случае с "возвратом" Jmp _2
    15. _2:
    16.   LoopNZd _1
    естественно при работе внутри цикла (_1:) eBx, eDx и даже
    eSi c eCx могут меняться для следующих этапов "дерева" разбора!
    Простой пример:
    попался комментарий '#'
    Код (ASM):
    1. _NextLine Proc  ; для  Call  [eDx + eAx * 4]
    2.   Mov  eDi, eSi
    3.   Mov  Al, 10 ; конец строки
    4.   RepNE  ScasB
    5.   Mov  eSi, eDi
    6.   Test  eCx, eCx
    7.   Ret
    8. _NextLine EndP
    Возникает простой вопрос - может ли быть более 1-го токена в строке? Если не может, то после него... до конца строки включительно рассматривать нечего, в вами приведенном коде, и т.д. и т.п.
    Я пока не планирую процессор мощнее (E8400 у меня), но интересно, ~во сколько VPCMPISTRI быстрее ее аналога выше?
    P.S. От ошибок никто не застрахован.(((
    Либо 13,10, либо 0Dh, 0Ah.
     
    Последнее редактирование модератором: 17 авг 2026
  18. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    195
    Сначала по другому было:
    Код (ASM):
    1.   Mov  eSi, Что разобрать
    2.   Mov  eCx, Сколько максимально -
    3. ; Т.Е. длина файла eCx и ([eSi+eCx]=0=EoF) должен находиться
    4. ; "вне" файла и рассмотрение его избыточно !
    5.   ClD  ; / StD - направление
    6.   xOr  eAx, eAx
    7.   LEA  eDx, [CallTab1]  ; или [JmpTab1]
    8. _1:
    9.   LodsB  ; например
    10.   Call  [eDx + eAx * 4]  ; если надо почитабельнее
    11. ;  Jmp  [eDx + eAx * 4]  ; как в вашем случае с "возвратом" на _2
    12. ; в JmpTab1  dd  _2 ; для необрабатывемых
    13.  _2:
    14.   LoopD _1
    15.  
    16. _NextLine Proc  ; для  Call  [eDx + eAx * 4]
    17.   Mov  eDi, eSi
    18.   Mov  Al, 10 ; конец строки
    19.   RepNE  ScasB
    20.   Mov  eSi, eDi
    21.   Cmp  eCx, 1  ;;
    22.   AdC  eCx, 0  ; так надежнее при возврате на _2:
    23.   Ret
    24. _NextLine EndP
    потом подумал улучшить... и в конце - 1-ну инструкцию "пожалел" и ошибся - может неконролируемо вывалиться:
    Код (ASM):
    1. ....
    2.   xOr  eAx, eAx  ; ZF=1 в самом начале по JnC _2
    3. ....
    4.   JnC _2
    5. ....
    6.  _2:
    7.   LoopNZd _1  ; при уходе на
    8. .....
    9. _Ret Proc  ; для  Call  [eDx + eAx * 4]
    10.   Ret
    11. _Ret EndP
    12. ....
    13. ;или  в при  JmpTab1  dd  _2 ; для необрабатывемых
    P.S. У меня сейчас есть задачи обработки строк методом проб и ошибок))) поэтому возможно даже излишне активен в теме.
     
    Последнее редактирование модератором: 17 авг 2026
  19. Application

    Application Moderator Команда форума

    Публикаций:
    1
    Регистрация:
    8 дек 2007
    Сообщения:
    1.025
    Можно сделать надежно(элитный способ) для подгрузки сторонних проектов(если не известно какое будет форматирование/мусорные токены), но при этом будет больше вычислений, сам код при этом будет гораздо лаконичнее. Либо 2 варианта загрузки(я так обычно не делаю): быстрый(обработка переносов/мусорных токенов - как у вас) и медленный(максимально надежный, но там немного другая логика).
     
  20. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    98
    А в этом и особенность низкоуровневого подхода.
    Когда я пишу на ассемблере, я не думаю о конструкциях Select Case, While или If.
    Это касается и организации главного цикла, и обработчика сообщений, и парсера.

    Когда я обрабатываю сообщения, я просто пробегаю по условиям в порядке их вероятности и/или критичности:
    Код (ASM):
    1. ;Messages Arranged by Probability
    2. cmp edx,111h
    3. je lbl_wmCommand ;Самое ожидаемое
    4. cmp edx,5
    5. je lbl_wmSize ;Приходит несколько раз
    6. cmp edx,10h
    7. je lbl_wmClose ;Один либо несколько раз, если юзер передумает
    8. cmp edx,2
    9. je lbl_wmDestroy ;Ждём единственного случая
    10. cmp edx,1
    11. je lbl_wmCreate ;Один раз в начале, дальше - балласт
    12. ;None of the Above
    13. call DefWindowProcA
    14.  
    Аналогично в парсере:
    Код (ASM):
    1. ;Token detection. Arranged by Probability
    2. ;mov rcx,pCurrentPosition
    3. cmp byte ptr[rcx],76h ;"v" - Вершин будут десятки тысяч
    4. je lbl_TokenStartsWithV
    5. cmp byte ptr[rcx],66h ;"f" - Полигонов будут тысячи
    6. je lbl_TokenFace
    7. cmp byte ptr[rcx],67h ;"g" - Несколько десятков групп
    8. je lbl_TokenGroup
    9. cmp dword ptr[rcx],6D657375h ;"usem" in reverse order - part of "usemtl" - Материалов наберётся с десяток
    10. je lbl_TokenUseMtl
    11. cmp byte ptr[rcx],6Fh ;"o" - Несколько объектов
    12. je lbl_TokenObject
    13. cmp dword ptr[rcx],6C6C746Dh; "mtll" in reverse order - part of "mtllib" - Одна или пара библиотек
    14. je lbl_TokenMtlLib
    15. jmp lbl_SkipByte
    Но: до разбора токенов надо ещё добраться!
    Допустим, я на первом проходе считаю количество токенов, чтобы узнать размер выделяемой памяти.
    Вот типичная строка:
    f -97/-112/-128 -81/-88/-104 -82/-89/-105
    Я увидел токен f и увеличил inc gnTotalFaces. После этого остаток строки мне не нужен.
    Теперь мне нужно искать 13h,10h либо EoF.
    Я не буду гонять через память каждый байт инструкциями lodsb/cmpsb, я лучше загружу сразу 16 байт и проверю их внутри CPU.

    Вопрос по существу.
    Вразумительных отчётов я не видел (хотя и не искал особо), мне сейчас интереснее проверить на своём опыте.
    Очень может быть, что Вы правы, и для перебора строк лучше побайтовые команды.
    Но у меня сейчас такое приложение, в котором мозги уже переключились на векторный подход,
    поэтому хочется выдержать чистоту жанра.