// LOADING CHAR FROM CUSTOM FONT FOR ALL LINE make_char_line_in_scratch: addiu sp, sp,-0x18 sw ra, 0x10(sp) sw t5, 0x14(sp) move t5, a0 //char num sll s3, a1, 0x2 //width in bytes (sprite count * 4) lui t7, MyAddr addiu t7, -0x0c //Text buffer pointer char_data_clear: move a1, t3 //dest address addiu a0, a1, 0x184 li v0, 0 char_data_loop: sw v0, 0x0(a1) addiu a1, 0x4 bne a1, a0, char_data_loop nop move s1, t3 // destination address reset li a2, 0 // char index counter lbu v0, 0x0(t7) lbu t2, 0xac(gp) //load color addiu t7, t7, 0x01 lui a3, 0x1f80 ori a3, a3,0x390 // set scratch convert addr r7 = 1f8002e0 chars_font_loop: addiu v0, -0x20 //shift unprintable beq v0, zero, spaceJump //If space (0x20 ASCII) -- bypass char nop lui v1, 0x801f // //load font addr to r3 (801ef000 + BA00) ori v1, v1, 0xaa00 // ==== 801faa00 sll t0, v0, 2 // t0 = v0 * 4 sll v0, v0, 3 // v0 = v0 * 8 addu v0, v0, t0 // v0 = (v0*8) + (v0*4) = v0*12 addu t1, v0, v1 //t1 = char addr // t1 = r2(offs) + r3 (start) clear t3 //new lines counter char_lines_loop: lbu v1, 0x0(t1) //load byte of char font to r3 nop beq v1, zero, zero_jump nop its_not_empty: //right andi a0, v1, 0xf // a0 = r3 & 0f - cutting left semibyte sll a0, a0, 0x1 // a0 << 1 addu a0, a0, a3 // a0 += bit table lhu a0, 0x0(a0) // в a0 - правый полусимвол в 4 бит //left srl a1, v1, 0x4 // r3 >> 4 andi a1, a1, 0xf // r2 = r3 & 0f sll a1, a1, 0x1 // r2 << 1 addu a1, a1, a3 // r2 = r2 + to4bitConvertTableAddr (r7) lhu a1, 0x0(a1)//>DAT_1f8002e0 в a1 - левый полусимвол в 4 бит nop //combine & color sll a1, 0x10 or a0, a1 mult a0, t2 //set color - сохраняем в регистре умножения готовые 4 байта //line dest addr calc - // s1(dest addr) + ((current line * (charcount * 4) + charIndex * 3)) //calc char index * 3 sll a1, a2, 1 addu a1, a1, a2 //getting final char line word... nop mflo t4 // t4 = final char //multiplying current line * width mult t3, s3 nop nop nop mflo a0 //getting final address addu a0, a0, a1 // a0 = current_line * width_in_bytes + charindex * 3 addu a0, a0, s1 // s1 = destination write address andi v0, t4, 0xFF // sb v0, 0x00(a0) // sra v0, t4, 0x08 // andi v0, v0, 0xFF // sb v0, 0x01(a0) // Byte by byte char data save in LITTLE ENDIAN sra v0, t4, 0x10 // cause we are not fitting to memory words andi v0, v0, 0xFF // sb v0, 0x02(a0) // addiu v0, t5, -0x1 bne a2, v0, not_last andi v1, t5, 0x3 beq v1, zero, divideby4 not_last: sra v0, t4, 0x18 // Байт рисуется только если длина не кратна 4 andi v0, v0, 0xFF // и это не последний байт sb v0, 0x03(a0) // (иначе происходит наложение байта на следующую строку) divideby4: zero_jump: addiu t3, t3, 0x01 //inc line counter li v0, 0x0C //line max count bne t3, v0, char_lines_loop //comparing... addiu t1, t1, 0x01 //shift char font line address spaceJump: addiu a2, a2, 0x1 // inc char index lbu v0, 0x0(t7) addiu t7, t7, 0x01 beq v0, zero, sprite_end //if we read 0 - end nop bne a2, t5, chars_font_loop // if r3 counter<>0 goto loop nop sprite_end: lbu v1, 0xad(gp) // >DAT_8007b23d_textMode load curText Shadow? li v0, 0x1 bne v1, v0, NotShadow //Shadow character check nop move a0, s1 nop make_shadow: //s3 - line width in bytes, a0 - data start move a1, s3 // a1 = ширина sll a1, 0x1 //a1 = смещение на 3 строку (ширина * 2) sll v0, s3, 3 //v0 = ширина строки * 8 addu v0, a1 //v0 = ширина строки * 10 addu a3, a0, v0 // a3 = указатель на 10 строку addu a0, a1 // a0 = Указатель на 3 строку lbu t1, 0xac(gp) // v0 = базовый цвет символа li t2, 0xf // t2 = маска 0xF для работы с 4 битами пикселя addiu t1, 0x1 // t1 = цвет тени (базовый цвет + 1) // Основной цикл по строкам (снизу вверх) shadow_row_loop: clear t5 //clear sprite shift counter //Цикл спрайтов в строке shadow_sprites_loop: addu t7, a3, t5 //Текущий адрес спрайта = Адрес текущей строки + смещение спрайта lw t0, 0x0(t7) // t0 = текущая полоса спрайта clear a2 // a2 = счётчик пикселей в строке (X координата) li a1, 0x4 // a1 = сдвиг 1 пиксель вправо (4 бита) // Внутренний цикл по пикселям в строке shadow_pixel_loop: move a1, a2 // a1 = текущий X пиксель addiu a1, a1, 0x1 // +1 пиксель вправо sll a1, a1, 0x2 // ×4 (перевод в биты) sll v0, a2, 0x2 // v0 = смещение исходного пикселя (X * 4) sllv v0, t2, v0 // v0 = маска для исходного пикселя and v0, t0, v0 // проверяем есть ли исходный пиксель beq v0, zero, no_s // если пикселя нет, пропускаем nop //Проверяем граничный случай (8-й пиксель) li v0, 0x7 // последний пиксель (X = 7) bne a2, v0, normal_case // если не 8-й пиксель - обычная обработка nop // Граничный случай: 8-й пиксель исходного спрайта // Тень будет в позиции a1 = 32 (8 × 4) - это следующий word! addu t8, t7, s3 // адрес следующей строки addiu t8, t8, 0x4 // переходим к следующему word lw v1, 0x0(t8) // загружаем следующий word li v0, 0xF // маска для ПЕРВОГО пикселя в новом word and v0, v1, v0 // проверяем занятость (биты 0-3 нового word) bne v0, zero, no_s // если занято - пропускаем nop move v0, t1 // цвет тени (в биты 0-3 нового word) or v0, v1, v0 // добавляем тень sw v0, 0x0(t8) // сохраняем b no_s nop normal_case: addu t8, t7, s3 // этот же word в следующей строке lw v1, 0x0(t8) // следующая строка sllv v0, t2, a1 // маска для пикселя тени and v0, v1, v0 // проверяем занятость bne v0, zero, no_s // если занято - пропускаем nop sllv v0, t1, a1 // цвет тени or v0, v1, v0 // добавляем тень sw v0, 0x0(t8) // сохраняем no_s: addiu a2, a2, 0x1 // следующий пиксель sltiu v0, a2, 0x8 // X < 8 (все 8 пикселей!) bne v0, zero, shadow_pixel_loop nop addiu t5, t5, 0x04 bne t5, s3, shadow_sprites_loop nop // next line subu a3, s3 //Двигаемся назад на ширину строки sltu v0, a3, a0 // проверяем вышли ли за верхнюю границу beq v0, zero, shadow_row_loop // продолжаем цикл по строкам nop NotShadow: lw t5,0x14(sp) lw ra,0x10(sp) //Restore stack and exit move v0, s1 jr ra addiu sp, sp, 0x18