; Ejemplo de fuente de 4x8 pixeles (64 caracteres por linea) ORG 35000 ld hl, charset_4x8-128 ; Inicio charset - (256/2) call Font_Set_Charset ld hl, cadena1 ld bc, $0400 ; X=00, Y=04 call Font_Set_XY call PrintString_4x8_Format loop: jr loop ret cadena1 DB "Fuente de 4x8", FONT_CRLF, FONT_CRLF DB "Esto es un texto impreso a 64 columnas con fuente " DB "de 4x8 pixeles. La letra tiene la mitad de anchura " DB "que la estandar pero todavia se lee con facilidad." DB FONT_CRLF, FONT_CRLF DB "Con esta fuente se pueden realizar juegos basados en " DB "texto pero hay que tener en cuenta que los atributos " DB FONT_SET_INK, 2, "afectan a 2 caracteres ", FONT_SET_INK, 0 DB "a la vez, por lo que es mejor no cambiar el paper y " DB "modificarlos solo antes o tras un espacio." DB FONT_EOS ;------------------------------------------------------------- ; half width 4x8 font - 384 bytes charset_4x8: DB $00,$02,$02,$02,$02,$00,$02,$00,$00,$52,$57,$02,$02,$07,$02,$00 DB $00,$25,$71,$62,$32,$74,$25,$00,$00,$22,$42,$30,$50,$50,$30,$00 DB $00,$14,$22,$41,$41,$41,$22,$14,$00,$20,$70,$22,$57,$02,$00,$00 DB $00,$00,$00,$00,$07,$00,$20,$20,$00,$01,$01,$02,$02,$04,$14,$00 DB $00,$22,$56,$52,$52,$52,$27,$00,$00,$27,$51,$12,$21,$45,$72,$00 DB $00,$57,$54,$56,$71,$15,$12,$00,$00,$17,$21,$61,$52,$52,$22,$00 DB $00,$22,$55,$25,$53,$52,$24,$00,$00,$00,$00,$22,$00,$00,$22,$02 DB $00,$00,$10,$27,$40,$27,$10,$00,$00,$02,$45,$21,$12,$20,$42,$00 DB $00,$23,$55,$75,$77,$45,$35,$00,$00,$63,$54,$64,$54,$54,$63,$00 DB $00,$67,$54,$56,$54,$54,$67,$00,$00,$73,$44,$64,$45,$45,$43,$00 DB $00,$57,$52,$72,$52,$52,$57,$00,$00,$35,$15,$16,$55,$55,$25,$00 DB $00,$45,$47,$45,$45,$45,$75,$00,$00,$62,$55,$55,$55,$55,$52,$00 DB $00,$62,$55,$55,$65,$45,$43,$00,$00,$63,$54,$52,$61,$55,$52,$00 DB $00,$75,$25,$25,$25,$25,$22,$00,$00,$55,$55,$55,$55,$27,$25,$00 DB $00,$55,$55,$25,$22,$52,$52,$00,$00,$73,$12,$22,$22,$42,$72,$03 DB $00,$46,$42,$22,$22,$12,$12,$06,$00,$20,$50,$00,$00,$00,$00,$0f DB $00,$20,$10,$03,$05,$05,$03,$00,$00,$40,$40,$63,$54,$54,$63,$00 DB $00,$10,$10,$32,$55,$56,$33,$00,$00,$10,$20,$73,$25,$25,$43,$06 DB $00,$42,$40,$66,$52,$52,$57,$00,$00,$14,$04,$35,$16,$15,$55,$20 DB $00,$60,$20,$25,$27,$25,$75,$00,$00,$00,$00,$62,$55,$55,$52,$00 DB $00,$00,$00,$63,$55,$55,$63,$41,$00,$00,$00,$53,$66,$43,$46,$00 DB $00,$00,$20,$75,$25,$25,$12,$00,$00,$00,$00,$55,$55,$27,$25,$00 DB $00,$00,$00,$55,$25,$25,$53,$06,$00,$01,$02,$72,$34,$62,$72,$01 DB $00,$24,$22,$22,$21,$22,$22,$04,$00,$56,$a9,$06,$04,$06,$09,$06 ;------------------------------------------------------------- FONT_CHARSET DW $3d00-256 FONT_ATTRIB DB 56 FONT_STYLE DB 0 FONT_X DB 0 FONT_Y DB 0 FONT_SCRWIDTH EQU 64 FONT_SCRHEIGHT EQU 24 FONT_NORMAL EQU 0 FONT_BOLD EQU 1 FONT_UNDERSC EQU 2 FONT_ITALIC EQU 3 FONT_EOS EQU 0 FONT_SET_STYLE EQU 1 FONT_SET_X EQU 2 FONT_SET_Y EQU 3 FONT_SET_INK EQU 4 FONT_SET_PAPER EQU 5 FONT_SET_ATTRIB EQU 6 FONT_SET_BRIGHT EQU 7 FONT_SET_FLASH EQU 8 FONT_XXXXXX EQU 9 ; Libre para ampliaciones FONT_LF EQU 10 FONT_CRLF EQU 11 FONT_BLANK EQU 12 FONT_CR EQU 13 FONT_BACKSPACE EQU 14 FONT_TAB EQU 15 FONT_INC_X EQU 16 ; De la 17 a la 31 libres ;------------------------------------------------------------- ; Tabla con las direcciones de las 16 rutinas de cambio. Notese ; que la numero 9 queda libre para una posible ampliacion. ;------------------------------------------------------------- FONT_CALL_JUMP_TABLE: DW Font_Set_Style, Font_Set_X, Font_Set_Y, Font_Set_Ink DW Font_Set_Paper, Font_Set_Attrib, Font_Set_Bright DW Font_Set_Flash, 0000, Font_LF, Font_CRLF, Font_Blank DW Font_CR, Font_Backspace, Font_Tab, Font_Inc_X ;------------------------------------------------------------- ; Establecer el CHARSET en USO ; Entrada : HL = direccion del charset en memoria ;------------------------------------------------------------- Font_Set_Charset: ld (FONT_CHARSET), hl ret ;------------------------------------------------------------- ; Establecer el estilo de texto en uso. ; Entrada : A = estilo ;------------------------------------------------------------- Font_Set_Style: ld (FONT_STYLE), a ret ;------------------------------------------------------------- ; Establecer la coordenada X en pantalla. ; Entrada : A = coordenada X ;------------------------------------------------------------- Font_Set_X: ld (FONT_X), a ret ;------------------------------------------------------------- ; Establecer la coordenada Y en pantalla. ; Entrada : A = coordenada Y ;------------------------------------------------------------- Font_Set_Y: ld (FONT_Y), a ret ;------------------------------------------------------------- ; Establecer la posicion X,Y del curso de fuente en pantalla. ; Entrada : B = Coordenada Y ; C = Coordenada X ;------------------------------------------------------------- Font_Set_XY: ld (FONT_X), bc ret ;------------------------------------------------------------- ; Establecer un valor de tinta para el atributo en curso. ; Entrada : A = Tinta (0-7) ; Modifica: AF ;------------------------------------------------------------- Font_Set_Ink: push bc ; Preservamos registros and 7 ; Borramos bits 7-3 ld b, a ; Lo guardamos en B ld a, (FONT_ATTRIB) ; Cogemos el atributo actual and %11111000 ; Borramos el valor de INK or b ; Insertamos INK en A ld (FONT_ATTRIB), a ; Guardamos el valor de INK pop bc ret ;------------------------------------------------------------- ; Establecer un valor de papel para el atributo en curso. ; Entrada : A = Papel (0-7) ; Modifica: AF ;------------------------------------------------------------- Font_Set_Paper: push bc ; Preservamos registros and 7 ; Borramos bits 7-3 rlca ; A = 00000XXX -> 0000XXX0 rlca ; A = 000XXX00 rlca ; A = 00XXX000 <-- Valor en paper ld b, a ; Lo guardamos en B ld a, (FONT_ATTRIB) ; Cogemos el atributo actual and %11000111 ; Borramos los datos de PAPER or b ; Insertamos PAPER en A ld (FONT_ATTRIB), a ; Guardamos el valor de PaPER pop bc ret ;------------------------------------------------------------- ; Establecer un valor de atributo para la impresion. ; Entrada : A = Tinta ;------------------------------------------------------------- Font_Set_Attrib: ld (FONT_ATTRIB), a ret ;------------------------------------------------------------- ; Establecer un valor de brillo (1/0) en el atributo actual. ; Entrada : A = Brillo (0-7) ; Modifica: AF ;------------------------------------------------------------- Font_Set_Bright: and 1 ; A = solo bit 0 de A ld a, (FONT_ATTRIB) ; Cargamos en A el atributo jr nz, fsbright_1 ; Si el bit solicitado era res 6, a ; Seteamos a 0 el bit de flash ld (FONT_ATTRIB), a ; Escribimos el atributo ret fsbright_1: set 6, a ; Seteamos a 1 el bit de brillo ld (FONT_ATTRIB), a ; Escribimos el atributo ret ;------------------------------------------------------------- ; Establecer un valor de flash (1/0) en el atributo actual. ; Entrada : A = Flash (1/0) ; Modifica: AF ;------------------------------------------------------------- Font_Set_Flash: and 1 ; A = solo bit 0 de A ld a, (FONT_ATTRIB) ; Cargamos en A el atributo jr nz, fsflash_1 ; Si el bit solicitado era res 7, a ; Seteamos a 0 el bit de flash ld (FONT_ATTRIB), a ; Escribimos el atributo ret fsflash_1: set 7, a ; Seteamos a 1 el bit de flash ld (FONT_ATTRIB), a ; Escribimos el atributo ret ;------------------------------------------------------------- ; Imprime un espacio, sobreescribiendo la posicion actual del ; cursor e incrementando X en una unidad. ; de la pantalla (actualizando Y en consecuencia). ; Modifica: AF ;------------------------------------------------------------- Font_Blank: ld a, ' ' ; Imprimir caracter espacio push bc push de push hl call PrintChar_4x8 ; Sobreescribir caracter pop hl pop de pop bc call Font_Inc_X ; Incrementamos la coord X ret ;------------------------------------------------------------- ; Incrementa en 1 la coordenada X teniendo en cuenta el borde ; de la pantalla (actualizando Y en consecuencia). ; Modifica: AF ;------------------------------------------------------------- Font_Inc_X: ld a, (FONT_X) ; Incrementamos la X inc a ; pero comprobamos si borde derecho cp FONT_SCRWIDTH-1 ; X > ANCHO-1? jr c, fincx_noedgex ; No, se puede guardar el valor call Font_CRLF ret fincx_noedgex: ld (FONT_X), a ; Establecemos el valor de X ret ;------------------------------------------------------------- ; Produce un LineFeed (incrementa Y en 1). Tiene en cuenta ; las variables de altura de la pantalla. ; Modifica: AF ;------------------------------------------------------------- Font_LF: ld a, (FONT_Y) ; Cogemos coordenada Y cp FONT_SCRHEIGHT-1 ; Estamos en la parte inferior jr nc, fontlf_noedge ; de pantalla? -> No avanzar inc a ; No estamos, avanzar ld (FONT_Y), a fontlf_noedge: ret ;------------------------------------------------------------- ; Produce un Retorno de Carro (Carriage Return) -> X=0. ; Modifica: AF ;------------------------------------------------------------- Font_CR: xor a ld (FONT_X), a ret ;------------------------------------------------------------- ; Provoca un LF y un CR en ese orden. ; Modifica: AF ;------------------------------------------------------------- Font_CRLF: call Font_LF call Font_CR ret ;------------------------------------------------------------- ; Imprime un tabulador (3 espacios) mediante PrintString. ; Modifica: AF ;------------------------------------------------------------- Font_Tab: push bc push de push hl ld hl, font_tab_string call PrintString_4x8_Format ; Imprimimos 3 espacios pop hl pop de pop bc ret font_tab_string DB " ", 0 ;------------------------------------------------------------- ; Decrementa la coordenada X, simultando un backspace. ; No realiza el borrado en si. ; Modifica: AF ;------------------------------------------------------------- Font_Dec_X: ld a, (FONT_X) ; Cargamos la coordenada X or a ret z ; Es cero? no se hace nada (salir) dec a ; No es cero? Decrementar ld (FONT_X), a ret ; Salir ;------------------------------------------------------------- ; Decrementa la coordenada X, simultando un backspace. No ; realiza el borrado en si. ; Modifica: AF ;------------------------------------------------------------- Font_Backspace: call Font_Dec_X ld a, ' ' ; Imprimir caracter espacio push bc push de push hl call PrintChar_4x8 ; Sobreescribir caracter pop hl pop de pop bc ret ; Salir ;------------------------------------------------------------- ; PrintString_4x8_Format: ; Imprime una cadena de texto de un charset de fuente 4x8. ; ; Entrada (paso por parametros en memoria): ; ----------------------------------------------------- ; FONT_CHARSET = Direccion de memoria del charset. ; FONT_X = Coordenada X en baja resolucion (0-31) ; FONT_Y = Coordenada Y en baja resolucion (0-23) ; FONT_ATTRIB = Atributo a utilizar en la impresion. ; Registro HL = Puntero a la cadena de texto a imprimir. ; Debe acabar en cero (FONT_EOS). ; Usa: DE, BC ;------------------------------------------------------------- PrintString_4x8_Format: ;;; Bucle de impresion de caracter pstring4_loop: ld a, (hl) ; Leemos un caracter de la cadena inc hl ; Apuntamos al siguiente caracter cp 32 ; Es menor que 32? jp c, pstring4_ccontrol ; Si, es un codigo de control, saltar push hl ; Salvaguardamos HL call PrintChar_4x8 ; Imprimimos el caracter pop hl ; Recuperamos HL ;;; Avanzamos el cursor usando Font_Blank, que incrementa X ;;; y actualiza X e Y si se llega al borde de la pantalla call Font_Inc_X ; Avanzar coordenada X jr pstring4_loop ; Continuar impresion hasta CHAR=0 pstring4_ccontrol: or a ; A es cero? ret z ; Si es 0 (fin de cadena) volver ;;; Si estamos aqui es porque es un codigo de control distinto > 0 ;;; Ahora debemos calcular la direccion de la rutina que lo atendera. ;;; Calculamos la direccion destino a la que saltar usando ;;; la tabla de saltos y el codigo de control como indice ex de, hl ld hl, FONT_CALL_JUMP_TABLE dec a ; Decrementamos A (puntero en tabla) rlca ; A = A * 2 = codigo de control * 2 ld c, a ld b, 0 ; BC = A*2 add hl, bc ; HL = DIR FONT_CALL_JUMP_TABLE+(CodControl*2) ld c, (hl) inc hl ld h, (hl) ld l, c ; Leemos la direccion de la tabla en HL ;;; Si CCONTROL>0 y CCONTROL<10 -> recoger parametro y saltar a rutina ;;; Si CCONTROL>9 y CCONTROL<32 -> saltar a rutina sin recogida cp 18 ; Comprobamos si (CCONTROL-1)*2 < 18 jp nc, pstring4_noparam ; Es decir, si CCONTROL > 9, no hay param ;;; Si CCONTROL < 10 -> recoger parametro: ld a, (de) ; Cogemos el parametro en cuestion de la cadena inc de ; Apuntamos al siguiente caracter ;;; Realizamos el salto a la rutina con o sin parametro recogido pstring4_noparam: ld bc, pstring4_retaddr ; Ponemos en BC la dir de retorno push bc ; Hacemos un push de la dir de retorno jp (hl) ; Saltamos a la rutina seleccionada ;;; Este es el punto al que volvemos tras la rutina pstring4_retaddr: ex de, hl ; Recuperamos en HL el puntero a cadena jr pstring4_loop ; Continuamos en el bucle ;------------------------------------------------------------- ; PrintChar_4x8: ; Imprime un caracter de 4x8 pixeles de un charset. ; ; Entrada (paso por parametros en memoria): ; ----------------------------------------------------- ; FONT_CHARSET = Direccion de memoria del charset. ; FONT_X = Coordenada X en baja resolucion (0-31) ; FONT_Y = Coordenada Y en baja resolucion (0-23) ; FONT_ATTRIB = Atributo a utilizar en la impresion. ; Registro A = ASCII del caracter a dibujar. ;------------------------------------------------------------- PrintChar_4x8: rra ; Dividimos A por 2 (resto en CF) push af ; Guardamos caracter y CF en A' ;;; Calcular posicion origen (array fuente) en HL como: ;;; direccion = base_charset + ((CARACTER/2)*8) ld bc, (FONT_CHARSET) ld h, 0 ld l, a add hl, hl add hl, hl add hl, hl add hl, bc ; HL = Direccion origen de A en fuente ;;; Calculamos las coordenadas destino de pantalla en DE: ld bc, (FONT_X) ; B = Y, C = X rr c ld a, b and $18 add a, $40 ld d, a ld a, b and 7 rrca rrca rrca add a, c ld e, a ; DE contiene ahora la direccion destino. ;;; Calculamos posiciĆ³n en pantalla. Tenemos que dividirla por 2 porque ;;; en cada columna de pantalla caben 2 caracteres. Usaremos el resto ;;; (Carry) para saber si va en la izq (CF=0) o der (CF=1) del caracter. ld a, (FONT_X) ; Volvemos a leer coordenada X rra ; Dividimos por 2 (posicion X en pantalla) ; Ademas el carry tiene el resto (par/impar) jr nc, pchar4_x_odd ; Saltar si es columna impar (por el CF) ;;; Ahora tenemos que imprimir el caracter en pantalla. Hemos saltado ;;; a pchar4_x_even o pchar4_x_odd segun si la posicion en pantalla es ;;; par o impar, pero cada una de estas 2 opciones nos da la posibilidad ;;; de usar una rutina u otra segun si el caracter ASCII es par o impar ;;; ya que tenemos que cogerlo de la fuente de una forma u otra ;;; Posicion de columna en pantalla par: pchar4_x_even : pop af ; Restaura A=char y CF=si es char par/impar jr c, pchar4_l_on_l jr pchar4_r_on_l pchar4_x_odd: pop af ; Restaura A=char y CF=si es char par/impar jr nc, pchar4_r_on_r jr pchar4_l_on_r pchar4_continue: ;;; Impresion de los atributos pchar4_printattr: ld a, d ; Recuperamos el valor inicial de DE sub 8 ; Restando los 8 scanlines avanzados ;;; Calcular posicion destino en area de atributos en HL. rrca ; A ya es = D, listo para rotar rrca ; Codigo de Get_Attr_Offset_From_Image rrca and 3 or $58 ld h, a ld l, e ;;; Escribir el atributo en memoria ld a, (FONT_ATTRIB) ld (hl), a ; Escribimos el atributo en memoria ret ;;;------------------------------------------------------------------ ;;; "Subrutinas" de impresion de caracter de 4x8 ;;; Entrada: HL = posicion del caracter en la fuente 4x8 ;;; DE = posicion en pantalla del primer scanline ;;;------------------------------------------------------------------ ;;;---------------------------------------------------- pchar4_l_on_l: ld b, 8 ; 8 scanlines / iteraciones pchar4_ll_lp: ld a, (de) ; Leer byte de la pantalla and %11110000 ld c, a ; Nos lo guardamos en C ld a, (hl) ; Cogemos el byte de la fuente and %00001111 or c ; Lo combinamos con el fondo ld (de), a ; Y lo escribimos en pantalla inc d ; Siguiente scanline inc hl ; Siguiente dato del "sprite" djnz pchar4_ll_lp jr pchar4_continue ; Volver tras impresion ;;;---------------------------------------------------- pchar4_r_on_r: ld b, 8 ; 8 scanlines / iteraciones pchar4_rr_lp: ld a, (de) ; Leer byte de la pantalla and %00001111 ld c, a ; Nos lo guardamos en C ld a, (hl) ; Cogemos el byte de la fuente and %11110000 or c ; Lo combinamos con el fondo ld (de), a ; Y lo escribimos en pantalla inc d ; Siguiente scanline inc hl ; Siguiente dato del "sprite" djnz pchar4_rr_lp jr pchar4_continue ; Volver tras impresion ;;;---------------------------------------------------- pchar4_l_on_r: ld b, 8 ; 8 scanlines / iteraciones pchar4_lr_lp: ld a, (de) ; Leer byte de la pantalla and %00001111 ld c, a ; Nos lo guardamos en C ld a, (hl) ; Cogemos el byte de la fuente rrca ; Lo desplazamos 4 veces >> dejando rrca ; lo bits 4 al 7 vacios rrca rrca and %11110000 or c ; Lo combinamos con el fondo ld (de), a ; Y lo escribimos en pantalla inc d ; Siguiente scanline inc hl ; Siguiente dato del "sprite" djnz pchar4_lr_lp jr pchar4_continue ; Volver tras impresion ;;;---------------------------------------------------- pchar4_r_on_l: ld b, 8 ; 8 scanlines / iteraciones pchar4_rl_lp: ld a, (de) ; Leer byte de la pantalla and %11110000 ld c, a ; Nos lo guardamos en C ld a, (hl) ; Cogemos el byte de la fuente rlca ; Lo desplazamos 4 veces << dejando rlca ; los bits 0 al 3 vacios rlca rlca and %00001111 or c ; Lo combinamos con el fondo ld (de), a ; Y lo escribimos en pantalla inc d ; Siguiente scanline inc hl ; Siguiente dato del "sprite" djnz pchar4_rl_lp jr pchar4_continue ; Volver tras impresion END 35000