]> 4ch.mooo.com Git - 16.git/blobdiff - 16/scrasm/SPRITE.INC
modified: 16/DOS_GFX.EXE
[16.git] / 16 / scrasm / SPRITE.INC
diff --git a/16/scrasm/SPRITE.INC b/16/scrasm/SPRITE.INC
new file mode 100644 (file)
index 0000000..9c3f2e4
--- /dev/null
@@ -0,0 +1,280 @@
+; SPRITE routines\r
+MAX_SPRITE      EQU     100\r
+\r
+RECTANGLE STRUCT 2,NONUNIQUE\r
+                X       WORD    0\r
+                Y       WORD    0\r
+                Wid4    BYTE    0\r
+                Ht      BYTE    0\r
+                Color   BYTE    0\r
+                Next    WORD    0\r
+        ; DrawMe is used to not bother with sprites that you know\r
+        ; are contained totally within another, allowing animated\r
+        ; eyes, etc to be stored in separate sprites.  These will be\r
+        ; drawn to the local buffer but skipped when copying to the\r
+        ; screen, so if they are not TOTALLY contained, they will\r
+        ; just get clipped away.\r
+                DrawMe  BYTE    1       ; default, yes draw me.\r
+        ; (Storage from this point on ... NEVER provide anything but\r
+        ; default for these values!)\r
+                address_virt    WORD    0\r
+                address_buf     WORD    0\r
+                next_line_virt  WORD    0\r
+                next_line_buf   WORD    0\r
+RECTANGLE ENDS\r
+\r
+SPRITE  STRUCT 2, NONUNIQUE\r
+        RECTANGLE       <>      ; Contains rectangle info\r
+SPRITE  ENDS\r
+\r
+EVEN\r
+rect5   SPRITE  <<40 ,60 , 2,8, C_TRANSPARENT, 0           , 0>>\r
+rect4   SPRITE  <<80 ,30 , 2,8, C_TRANSPARENT, offset rect5, 0>>\r
+rect3   SPRITE  <<120,60 , 2,8, C_TRANSPARENT, offset rect4, 0>>\r
+rect2   SPRITE  <<55 ,100, 2,8, C_TRANSPARENT, offset rect3, 0>>\r
+rect1   SPRITE  <<105,100, 2,8, C_TRANSPARENT, offset rect2, 0>>\r
+\r
+rect6   SPRITE  <<36 ,56 , 4,16, C_BLUE, offset rect1, 1>>\r
+rect7   SPRITE  <<76 ,26 , 4,16, C_BLUE, offset rect6, 1>>\r
+rect8   SPRITE  <<116,56 , 4,16, C_BLUE, offset rect7, 1>>\r
+rect9   SPRITE  <<51 ,96 , 4,16, C_BLUE, offset rect8, 1>>\r
+rect10  SPRITE  <<101,96 , 4,16, C_BLUE, offset rect9, 1>>\r
+\r
+;; Simply adding in these 5 rectangles (~20000 pixels for both\r
+;; drawing and erasing) really slows things down!  That's why\r
+;; it's important to optimize the sprite drawing routines!\r
+rect11  SPRITE  <<35 ,55 ,14,36, C_GREEN, offset rect10, 1>>\r
+rect12  SPRITE  <<75 ,25 ,14,36, C_GREEN, offset rect11, 1>>\r
+rect13  SPRITE  <<115,55 ,14,36, C_GREEN, offset rect12, 1>>\r
+rect14  SPRITE  <<50 ,95 ,14,36, C_GREEN, offset rect13, 1>>\r
+rect15  SPRITE  <<100,95 ,14,36, C_GREEN, offset rect14, 1>>\r
+\r
+FIRST_SPRITE    EQU     rect10\r
+\r
+EVEN\r
+AnimateSprites  PROC    near\r
+                ret\r
+        ; Blank out the draw page, by copying from the blank page\r
+        ; to the draw page all rectangles which had changed.  The\r
+        ; blank page must always be entirely blank if this is going\r
+        ; to work!\r
+                mov     di,cs:DrawPage.UpperLeftAddress\r
+                add     di,cs:DrawPage.ScrollOffset\r
+                mov     si,cs:BlankPage.UpperLeftAddress\r
+                add     si,cs:BlankPage.ScrollOffset\r
+                mov     bp,cs:BlankPage.Rectangles\r
+                call    CopyRectangles\r
+\r
+        ; Now draw the sprites.  Uses a temporary buffer to ensure\r
+        ; minimal drawing to the screen, but that's not really necessary,\r
+        ; if memory is at a minimum.  It's just faster...\r
+                mov     bp,offset FIRST_SPRITE\r
+                mov     cs:DrawPage.Rectangles,bp\r
+                call    do_fill_buffer\r
+                mov     di,cs:DrawPage.UpperLeftAddress\r
+                add     di,cs:DrawPage.ScrollOffset\r
+                mov     bh,cs:DrawPage.AlignmentMask\r
+                mov     bp,offset FIRST_SPRITE\r
+                jmp     smart_rects     ; "call"\r
+AnimateSprites  ENDP\r
+\r
+smart_dest      DW      0\r
+out_di          DW      0\r
+out_si          DW      0\r
+\r
+EVEN\r
+smart_rects     PROC    near\r
+                add     di,cs:DrawPage.Address\r
+                mov     ds,cs:segBuffer\r
+                mov     es,cs:segVideo\r
+                mov     dx,3c4h\r
+                mov     al,02h\r
+                out     dx,al\r
+                inc     dx\r
+                mov     cs:smart_dest,di\r
+\r
+        ; === Beginning of loop through rectangles! ===\r
+sp_nextrect:\r
+                cmp     cs:[bp].RECTANGLE.DrawMe,1\r
+                jne     sp_next\r
+        ; Draw this rectangle from the buffer to screen memory.\r
+        ; Calculate the output address.\r
+                mov     si,cs:[bp].RECTANGLE.address_buf\r
+                mov     di,cs:[bp].RECTANGLE.address_virt\r
+                add     di,cs:smart_dest\r
+\r
+        ; Loop over 4 planes\r
+                mov     bl,4\r
+sp_plane_loop:  mov     al,bh\r
+                out     dx,al\r
+\r
+                mov     cs:out_di,di\r
+                mov     cs:out_si,si\r
+\r
+        ; Loop over height\r
+                mov     ch,cs:[bp].RECTANGLE.Ht\r
+sp_row_loop:\r
+\r
+        ; Loop over width of rectangle (Wid4 is actually width/4)\r
+                mov     cl,cs:[bp].RECTANGLE.Wid4\r
+sp_col_loop:\r
+\r
+        ; Read a byte from the buffer\r
+        ; Is it transparent (no-modify)?  If so, just jump over the draw\r
+                mov     al,byte ptr ds:[si]\r
+                cmp     al,C_TRANSPARENT\r
+                je      sp_next_pixel\r
+        ; Otherwise, draw it on the spreen, and mark it transparent\r
+        ; so that it won't be drawn again.\r
+                mov     byte ptr es:[di],al\r
+                mov     byte ptr ds:[si],C_TRANSPARENT\r
+\r
+        ; Skip to next 4-byte group (next column that can be drawn in\r
+        ; Mode X)  Also increment spreen draw address, but only by 1\r
+        ; because ModeX is 4 pixels per byte\r
+sp_next_pixel:\r
+                add     si,4\r
+                inc     di\r
+\r
+                dec     cl\r
+                jnz     sp_col_loop\r
+\r
+        ; End of row.  Skip space to get to left edge of next row down\r
+        ;  Skip SI = (SCREEN_WIDTH - #bytesdrawn)\r
+        ; Only draw up to height of rectangle\r
+                add     si,cs:[bp].RECTANGLE.next_line_buf\r
+                add     di,cs:[bp].RECTANGLE.next_line_virt\r
+                dec     ch\r
+                jnz     sp_row_loop\r
+\r
+                mov     di,cs:out_di\r
+                mov     si,cs:out_si\r
+                inc     si\r
+                rol     bh,1\r
+                adc     di,0\r
+\r
+                dec     bl\r
+                jnz     sp_plane_loop\r
+\r
+        ; Follow chain to next rectangle\r
+sp_next:        mov     bp,cs:[bp].RECTANGLE.Next\r
+                cmp     bp,0\r
+                jne     sp_nextrect\r
+        ; All done\r
+sp_end:         ret\r
+smart_rects     ENDP\r
+\r
+; BP -> first rectangle.  Follows BP->next, stops when BP = 0\r
+EVEN\r
+do_fill_buffer  PROC    near\r
+                mov     es,cs:segBuffer\r
+\r
+                cmp     bp,0\r
+                je      fill_end\r
+fill_loop:\r
+\r
+                mov     bx,cs:[bp].RECTANGLE.Y\r
+                shl     bx,1                    ; BX = word index y\r
+                mov     di,cs:MultBufWidth[bx]  ; DI = SW * y\r
+                mov     cx,cs:[bp].RECTANGLE.X  ; CX = x\r
+                add     di,cx                   ; DI = (SW * y) + x\r
+                mov     cs:[bp].RECTANGLE.address_buf,di ; (DI used later)\r
+\r
+                mov     ax,cs:MultVirtWidth[bx] ; AX = (VW/4) * y\r
+                shr     cx,2                    ; CX = (x / 4)\r
+                add     ax,cx                   ; AX = (VW * y + x)/4\r
+                mov     cs:[bp].RECTANGLE.address_virt,ax\r
+\r
+                mov     dx,(VIRTUAL_WIDTH / 4)\r
+                sub     dl,cs:[bp].RECTANGLE.Wid4 ; DX = (VW - w) / 4\r
+                mov     cs:[bp].RECTANGLE.next_line_virt,dx\r
+\r
+                mov     dx,(SCREEN_WIDTH / 4)\r
+                sub     dl,cs:[bp].RECTANGLE.Wid4 ; DX = (SW - w) / 4\r
+                shl     dx,2                      ; DX = SW - w\r
+                mov     cs:[bp].RECTANGLE.next_line_buf,dx\r
+\r
+                mov     ah,cs:[bp].RECTANGLE.Color\r
+                mov     al,cs:[bp].RECTANGLE.Color\r
+\r
+                mov     ch,cs:[bp].RECTANGLE.Ht\r
+fill_row_loop:  mov     cl,cs:[bp].RECTANGLE.Wid4\r
+fill_col_loop:  mov     es:[di],ax\r
+                mov     es:[di+2],ax\r
+                add     di,4\r
+                dec     cl\r
+                jnz     fill_col_loop\r
+                add     di,dx\r
+                dec     ch\r
+                jnz     fill_row_loop\r
+\r
+                mov     bp,cs:[bp].RECTANGLE.Next\r
+                cmp     bp,0\r
+                jne     fill_loop\r
+fill_end:       ret\r
+do_fill_buffer  ENDP\r
+\r
+EVEN\r
+CopyRectangles  PROC    near\r
+                mov     ax,cs:segVideo\r
+                mov     ds,ax\r
+                mov     es,ax\r
+\r
+        ; Calculate the difference between the source and destination\r
+        ; pages.  Since in a movsb loop the two would remain a constant\r
+        ; distance apart, we can just calculate a displacement and then\r
+        ; not have to worry about SI; instead use DI and DI+BX, thanks\r
+        ; to the thoughtful x86 ALU!\r
+                mov     bx,di\r
+                sub     bx,si\r
+\r
+                mov     dx,GC_INDEX\r
+                mov     ax,ALL_COPY_BITS\r
+                out     dx,ax\r
+\r
+                mov     dx,SC_INDEX\r
+                mov     ax,0F02h\r
+                out     dx,ax\r
+                mov     si,di   ;store destination\r
+\r
+        ; === Beginning of loop through rectangles! ===\r
+cr_nextrect:    cmp     cs:[bp].RECTANGLE.DrawMe,1\r
+                jne     cr_next\r
+        ; Draw this rectangle from the buffer to screen memory.\r
+        ; Calculate the output address.\r
+                mov     di,cs:[bp].RECTANGLE.address_virt\r
+                mov     dx,cs:[bp].RECTANGLE.next_line_virt\r
+                add     di,si\r
+\r
+        ; Loop over height\r
+                mov     ch,cs:[bp].RECTANGLE.Ht\r
+cr_row_loop:\r
+\r
+        ; Loop over width of rectangle (Wid4 is actually width/4)\r
+                mov     cl,cs:[bp].RECTANGLE.Wid4\r
+cr_col_loop:    mov     al,ds:[di + bx]\r
+                stosb\r
+                dec     cl\r
+                jnz     cr_col_loop\r
+                mov     al,ds:[di + bx]\r
+                mov     es:[di],al\r
+\r
+        ; End of row.  Skip space to get to left edge of next row down\r
+        ; Only draw up to height of rectangle\r
+                add     di,dx\r
+                dec     ch\r
+                jnz     cr_row_loop\r
+\r
+        ; Follow chain to next rectangle\r
+cr_next:        mov     bp,cs:[bp].RECTANGLE.Next\r
+                cmp     bp,0\r
+                jne     cr_nextrect\r
+        ; All done\r
+cr_end:\r
+                mov     dx,GC_INDEX\r
+                mov     ax,ALL_DRAW_BITS\r
+                out     dx,ax\r
+                ret\r
+CopyRectangles  ENDP\r
+\r
+\1a
\ No newline at end of file