; ; Raw Game Engine ; Copyright (C) 2023 Ernest Deak ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; %include "inc/generic.inc" %include "inc/sdl2.inc" %include "include/rge.inc" BITS 64 DEFAULT REL global RG_Subsys_Img_init:function global RG_Load_png:function global AnimSprite_animate:function global AnimSprite_init:function global AnimSprite_calc_frame:function global AnimSprite_new:function section code_section ;; Initializes the image subsystem. Mostly just SDL2 init code for the image ;; plugin/module RG_Subsys_Img_init: funcstart stksetup exmcall IMG_Init, IMG_INIT_PNG | IMG_INIT_JPG ; init png lea areg1, fmt lea areg2, initstr exmcall printf funcend ;; Load an image as a texture for the renderer ;; @param SDL_Renderer* renderer = the sdl2 renderer ;; @param const char* filename_string = a string pointing to a filename ;; @return RAX = pointer to texture RG_Load_png: funcstart stksetup ; expecting parameter in areg2 with an address to a string ; for the filename and areg1 should contain the address of the renderer exmcall IMG_LoadTexture, areg1, areg2 test rax,rax jnz .ok exmcall SDL_GetError lea areg1, sdl_err_fmt mov areg2, rax exmcall printf xor rax,rax .ok: ; returns pointer to texture in rax, 0 on error and it gets printed ; on stdout funcend ;; Create a new animated sprite. ;; @param areg1 - pointer to area of memory with enough space to populate data ;; @param areg2 - frame width ;; @param areg3 - frame height ;; @return RAX - ptr to anim struct AnimSprite_new: funcstart stksetup call AnimSprite_init ; rax = areg1 = pointer to struct mov eax, 0 cvtsi2ss xmm8, eax movss [AnimSprite(areg1, dstrect) + SDL_rect.x], xmm8 movss [AnimSprite(areg1, dstrect) + SDL_rect.y], xmm8 ; set dimensions to frame size and coord at 0,0 mov eax, [AnimSprite(areg1, srcrect) + SDL_rect.w] cvtsi2ss xmm8, eax movss [AnimSprite(areg1, dstrect) + SDL_rect.w], xmm8 mov eax, [AnimSprite(areg1, srcrect) + SDL_rect.h] cvtsi2ss xmm8, eax movss [AnimSprite(areg1, dstrect) + SDL_rect.h], xmm8 ; set some animation defaults mov qword [AnimSprite(areg1, startframe) ], 0 mov qword [AnimSprite(areg1, endframe) ], 0 mov qword [AnimSprite(areg1, speed) ], 0 mov qword [AnimSprite(areg1, frame)], 0 mov qword [AnimSprite(areg1, dt_accum)], 0 mov qword [AnimSprite(areg1, visible)], 1 mov rax, areg1 ; return same pointer funcend ;; Initializes some structure data, like total width and height ;; it is necessary to call this for proper animation handling ;; It also must contain a valid img pointer to its texture ;; @param areg1 - ptr to anim sprite ;; @param areg2 - frame width ;; @param areg3 - frame height ;; @return RAX - ptr to anim sprite AnimSprite_init: funcstart var 8, %$access, %$format, %$sprite, %$w, %$h, %$fw, %$fh stksetup mov [%$sprite], areg1 mov [%$fw], areg2d mov [%$fh], areg3d mov areg1, [AnimSprite(areg1, img)] lea areg2, [%$format] lea areg3, [%$access] lea areg4, [%$w] lea areg5, [%$h] exmcall SDL_QueryTexture mov areg1, [%$sprite] ; NOTE to self: ; when using the variable variant of the helper macros ; the structure must actually be placed on the stack for it ; to work, and not being a pointer to the structure mov rax, [%$w] mov [AnimSprite(areg1, width)], eax mov rax, [%$h] mov [AnimSprite(areg1, height)], eax mov rax, [%$fw] mov [AnimSprite(areg1, srcrect) + SDL_rect.w], eax mov rax, [%$fh] mov [AnimSprite(areg1, srcrect) + SDL_rect.h], eax mov dword [AnimSprite(areg1, srcrect) + SDL_rect.x], 0 mov dword [AnimSprite(areg1, srcrect) + SDL_rect.y], 0 mov rax, areg1 ; return pointer to struct funcend ; FIXME: dont accumulate on null frames? or make sure to reset DT ; in code that needs instant transition to an animation ;; Function that advances the animation of an animated sprite by 1 frame ;; @param AnimSprite* ;; @param dt = delta time AnimSprite_animate: funcstart ; var 8, %$r15, %$rbx saveregs r15, rbx, rdx, r12, r13 var 8, %$dt stksetup ; areg1 = instance of AnimSprite ; areg2 = delta time localdef %$frame, r11 localdef %$endframe, r8 localdef %$startframe, r10 localdef %$animspeed, r15 mov [%$dt], areg2 mov %$frame, [AnimSprite(areg1, frame)] mov %$endframe, [AnimSprite(areg1, endframe)] mov %$startframe, [AnimSprite(areg1, startframe)] mov %$animspeed, [AnimSprite(areg1, speed)] test %$animspeed, %$animspeed jz .endfunc ;if speed 0, do not animate at all and return mov r9, [AnimSprite(areg1, dt_accum)] cmp r9, 1 jle .cont; less or equal to 1 ; else, accum. delta time ;add qword [AnimSprite(areg1, dt_accum)], areg2 add r9, areg2 xor r13,r13 cmp r9, %$animspeed cmovge r9, r13 mov [AnimSprite(areg1, dt_accum)], r9 jmp .endfunc .cont: ; begin accum add qword [AnimSprite(areg1, dt_accum)], areg2 ; continnue and clear delta time ;if frame is bellow the start frame, set it to the start frame mov r9, %$startframe cmp %$frame, %$startframe cmovb %$frame, r9 ; set frame to %$startframe if its above the endframe mov r9, %$startframe inc %$frame cmp %$frame,%$endframe cmovg %$frame, r9 mov [AnimSprite(areg1,frame)], %$frame ; calculate new X and Y position lea rbx, [AnimSprite(areg1, srcrect)] ; calculate new X position mov r9d, dword [SDL_rect(rbx,w)] xor rdx,rdx ; x = (frame * frame width) % total width ; r11 = frame ; rbx = ptr to sdl rect ; r9d = frame width mov eax, r9d mul %$frame ; eax = tmp result of x postition ( frame * frame width) mov r12d, dword [AnimSprite(areg1, width)] div r12d ; % total width ; eax = quotient, edx = remainder (modulus in this case (unsigned div)) ; x = edx mov [SDL_rect(rbx, x)], edx ; calculate Y position xor rdx,rdx ; y = quot(frame/num horiz. frames) * frame height mov eax, dword [AnimSprite(areg1, width)] ; load frame width ; r9d = frame width div r9d ; eax = num frames xor rdx,rdx mov r12d, eax mov rax, %$frame div r12d ; frame/num frames ; eax = quot(frame/num horiz. frames) mov r9d, [SDL_rect(rbx, h)] mul r9d ; * frame height ; eax = y mov dword [SDL_rect(rbx, y)], eax .endfunc: funcend ;; Calculate frame index of sprite based on row and column ;; The srcrect (SDL_rect) contains size of 1 frame ;; The pointed to AnimSprite must have been initialized with AnimSprite_init ;; before calling this function ;; @param areg1 - pointer to AnimSprite ;; @param areg2 - row ;; @param areg3 - column ;; @return RAX - frame index AnimSprite_calc_frame: funcstart saveregs rdx stksetup ; calculate horizontal frames mov rax, [AnimSprite(areg1, width)] mov r11d, [AnimSprite(areg1, srcrect) + SDL_rect.w] ; r11 = size of 1 horiz. frame ; NOTE: mind the dword size xor rdx,rdx div r11d ; rax = number of total horizontal frames mov r11, rax ; r11 = horizontal frames ; calc offset mov rax, areg2 mul r11 ; num hframes * row ; rax = first frame of row mov rdx, [%$saved_rdx] add rax, areg3 ; add column to index ; rax = index of selected frame (horizontal offset) funcend section ro_section fmt: db "RGE [Image]: %s",10,0 sdl_err_fmt: db "SDL2 [SDL_image] Error: %s",10,0 rge_img_fmt: db "RGE Error: %s",10,0 initstr: db "Image Subsystem initialized",0 hexfmt: db "RGE [dbg] Value: 0x%x",10,0 .