rem ================================================================== rem Mode 7 library. rem rem It's all fake. rem rem By Marcus. rem ================================================================== constant: M7_MAX_OBJECTS 200 M7_OBJ_ID 0 M7_OBJ_IMG 1 M7_OBJ_X 2 M7_OBJ_Z 3 M7_OBJ_Y 4 M7_OBJ_TX 5 M7_OBJ_TZ 6 M7_OBJ_XZ 7; rem unused. M7_OBJ_H 8 M7_OBJ_D 9 M7_OBJ_CEL 10 M7_X 0 M7_Z 1 M7_ANGLE 2 M7_FLAG 2 visible: rem Objects. m7_Objects#[M7_MAX_OBJECTS][11] m7_ObjOrder[M7_MAX_OBJECTS] m7_ObjCount = 0 rem Fog. m7_FogR m7_FogG m7_FogB m7_FogMin# m7_FogMax# m7_FogSpread# rem View. m7_ViewW m7_ViewH m7_MaxZ# rem Map. m7_MapW m7_MapH m7_Floor[][] m7_Flag[][] m7_Item[][] hidden: rem ================================================================== rem Init view. rem ================================================================== procedure M7_Init(w, h, zMax#) m7_Objects#[M7_MAX_OBJECTS][11] m7_ObjOrder[M7_MAX_OBJECTS] m7_ObjCount rc_FogR rc_FogG rc_FogB rc_FogMin# rc_FogMax# rc_FogSpread# m7_ViewW = w m7_ViewH = h m7_MapW m7_MapH m7_Floor[][] m7_Flag[][] m7_Item[][] m7_MaxZ = zMax endproc function M7_GetMapWidth() return m7_MapW endfunc function M7_GetMapHeight() return m7_MapH endfunc rem ================================================================== rem Render view. rem ================================================================== procedure M7_Render(viewx#, viewz#, viewy#, angle#, pitch, fov#) dx# dz# d# screenxstart# screendx# screendz# xi zi oldxi oldzi ustart# vstart# xf# zf# xk# zk# uend# vend# screenxend# screenzend# id viewy = max#(viewy, 0.01) fov = fov*0.5 vfov# = fov*float(m7_ViewH)/float(m7_ViewW) unit# = float(m7_ViewH/2)/tan(vfov) cosl# = cos(angle - fov) cosr# = cos(angle + fov) sinl# = sin(angle - fov) sinr# = sin(angle + fov) alpha for y = 0 to m7_ViewH - 1 if y - m7_ViewH/2 - pitch > 0 z# = unit*viewy/float(y - m7_ViewH/2 - pitch) z = z/cos(fov) if z < m7_MaxZ MOV# @1 z SUB# @1 m7_FogMin MUL# @1 m7_FogSpread FTI @1 MOV alpha @1 if alpha < 255 set color m7_FogR, m7_FogG, m7_FogB, alpha else set color 255, 255, 255, 0 endif xstart# = cosl*z + viewx xend# = cosr*z + viewx zstart# = sinl*z + viewz zend# = sinr*z + viewz MOV# dx xend SUB# dx xstart MOV# dz zend SUB# dz zstart MOV# d dx MUL# d d MOV# @0 dz MUL# @0 @0 ADD# d @0 d# = sqr(d) MOV# @0 1.0 DIV# @0 d MUL# dx @0 MUL# dz @0 MOV# screenxstart 0.0 MOV @0 m7_ViewW ITF @0 DIV# @0 d MOV# screendx @0 MOV# @0 xstart FTI @0 MOV xi @0 MOV# @0 zstart FTI @0 MOV zi @0 MOV# ustart xstart MOV# @0 xstart FTI @0 ITF @0 SUB# ustart @0 MOV# vstart zstart MOV# @0 zstart FTI @0 ITF @0 SUB# vstart @0 @r_row_loop: MOV oldxi xi MOV oldzi zi rem dx step. CMP# dx 0.0 JE# no_dx JG# dxp rem dx < 0 CMP oldxi 0 JL r_row_loop_end SUB xi 1 MOV @0 xi ADD @0 1 ITF @0 MOV# xf @0 MOV# xk xf SUB# xk xstart DIV# xk dx JMP dx_end @dxp: rem dx > 0 CMP oldxi m7_MapW JGE r_row_loop_end ADD xi 1 MOV @0 xi ITF @0 MOV# xf @0 MOV# xk xf SUB# xk xstart DIV# xk dx JMP dx_end @no_dx: MOV# xk 100000.0 @dx_end: rem dz step. CMP# dz 0.0 JE# no_dz JG# dzp rem dz < 0 CMP oldzi 0 JL r_row_loop_end SUB zi 1 MOV @0 zi ADD @0 1 ITF @0 MOV# zf @0 MOV# zk zf SUB# zk zstart DIV# zk dz JMP dz_end @dzp: rem dz > 0 CMP oldzi m7_MapH JGE r_row_loop_end ADD zi 1 MOV @0 zi ITF @0 MOV# zf @0 MOV# zk zf SUB# zk zstart DIV# zk dz JMP dz_end @no_dz: MOV# zk 100000.0 @dz_end: CMP# xk zk JG# r_zk rem if xk < zk CMP# dz 0.0 JE# r_dz_no_step JGE# r_dz_neg_step ADD zi 1 JMP r_dz_no_step @r_dz_neg_step: SUB zi 1 @r_dz_no_step: CMP# dx 0.0 JG# r_uone MOV# uend 0.0 JMP r_udone @r_uone: MOV# uend 1.0 @r_udone: MOV# xend xf MOV# zend xk MUL# zend dz ADD# zend zstart MOV# vend zend MOV# @0 zend FTI @0 ITF @0 SUB# vend @0 MOV# screenxend xk MUL# screenxend screendx ADD# screenxend screenxstart JMP r_zdone rem else @r_zk: CMP# dx 0.0 JE# r_dx_no_step JGE# r_dx_neg_step ADD xi 1 JMP r_dx_no_step @r_dx_neg_step: SUB xi 1 @r_dx_no_step: CMP# dz 0.0 JG# r_vone MOV# vend 0.0 JMP r_vdone @r_vone: MOV# vend 1.0 @r_vdone: MOV# zend zf MOV# xend zk MUL# xend dx ADD# xend xstart MOV# uend xend MOV# @0 xend FTI @0 ITF @0 SUB# uend @0 MOV# screenxend zk MUL# screenxend screendx ADD# screenxend screenxstart rem endif @r_zdone: CMP oldxi 0 JL no_floor_draw CMP oldxi m7_MapW JGE no_floor_draw CMP oldzi 0 JL no_floor_draw CMP oldzi m7_MapH JGE no_floor_draw MOV @1 oldxi MUL @1 m7_MapH ADD @1 oldzi MOV @0 m7_Floor STP @0 @1 CMP [@0] 0 JLE no_floor_draw PSH @1 MOV id [@0] draw hraster id, y, int(screenxstart), int(screenxend), ustart, vstart, uend, vend POP @1 @no_floor_draw: MOV# xstart xend MOV# zstart zend MOV# screenxstart screenxend rem Wrap u texture coordinate. CMP# uend 0.0 JE# r_u_zero CMP# uend 1.0 JE# r_u_one MOV# ustart uend JMP r_u_done @r_u_zero: MOV# ustart 1.0 JMP r_u_done @r_u_one: MOV# ustart 0.0 @r_u_done: rem Wrap v texture coordinate. CMP# vend 0.0 JE# r_v_zero CMP# vend 1.0 JE# r_v_one MOV# vstart vend JMP r_v_done @r_v_zero: MOV# vstart 1.0 JMP r_v_done @r_v_one: MOV# vstart 0.0 @r_v_done: MOV @0 m7_ViewW ITF @0 CMP# screenxend @0 JGE# r_row_loop_end JMP r_row_loop @r_row_loop_end: endif endif next proc M7_RenderObjects viewx, viewz, viewy, angle, pitch, fov*2.0 endproc procedure bla(msg$) set color 0, 0, 0 cls set color 255, 255, 255 set caret 0, 0 write msg redraw wait keydown endproc rem ================================================================== rem Render objects. rem ================================================================== procedure M7_RenderObjects(viewx#, viewz#, viewy#, angle#, pitch, fov#) proc M7_ProcessObjects viewx, viewz, angle vfov# = fov*float(m7_ViewH)/float(m7_ViewW) unit# = float(m7_ViewW/2)/tan(fov*0.5) index img cel for i = 0 to m7_ObjCount - 1 MOV @1 m7_ObjOrder STP @1 i MOV @1 [@1] MOV index @1 MUL @1 11 MOV# @0 m7_Objects STP# @0 @1 rem Check if object is active. CMP [@0] 0 JE m7_ro_break STP# @0 1 MOV img [@0] STP# @0 9 MOV cel [@0] u_x# = cos(angle) u_z# = sin(angle) v_x# = m7_Objects[index][M7_OBJ_X] - viewx v_z# = m7_Objects[index][M7_OBJ_Z] - viewz hyp# = sqr(v_x*v_x + v_z*v_z) if hyp = 0.0 then JMP m7_ro_continue k# = 1.0/hyp v_x = v_x*k v_z = v_z*k dp# = v_x*u_x + v_z*u_z if dp <= 0.1 then JMP m7_ro_continue if dp >= 1.0 a# = 0.0 else a# = acos(dp) endif d# = hyp*cos(a) if d < m7_MaxZ if u_x*v_z - u_z*v_x < 0.0 tx# = float(m7_ViewW/2) - unit*tan(a) else tx# = float(m7_ViewW/2) + unit*tan(a) endif unit# = float(m7_ViewH/2)/tan(vfov*0.5) ystart = int(unit*(viewy - m7_Objects[index][M7_OBJ_Y] - m7_Objects[index][M7_OBJ_H])/d + float(m7_ViewH/2 + pitch)) yend = int(unit*(viewy - m7_Objects[index][M7_OBJ_Y])/d + float(m7_ViewH/2 + pitch)) w = width(img)*(yend - ystart)/height(img) set color 255, 255, 255, 0 proc M7_DrawImage img, int(tx) - w/2, ystart, w, yend - ystart, cel%cols(img), cel/cols(img), d endif JMP m7_ro_continue @m7_ro_break: break @m7_ro_continue: next endproc procedure M7_DrawImage(img, imgx, imgy, w, h, col, row, z#) alpha MOV# @1 z SUB# @1 m7_FogMin MUL# @1 m7_FogSpread FTI @1 MOV alpha @1 if alpha < 255 set color m7_FogR, m7_FogG, m7_FogB, alpha else set color 255, 255, 255, 0 endif celw# = 1.0/float(cols(img)) celh# = 1.0/float(rows(img)) u# = float(col)*celw uend# = u + celw v# = float(row)*celh vend# = v + celh ustep# = celw#/float(w) if imgx < 0 u = u + ustep*float(-imgx) w = w + imgx imgx = 0 endif xend = min(imgx + w, m7_ViewW) h = imgy + h x MOV @0 imgx @m7_di_loop: CMP @0 xend JGE m7_di_loop_end MOV x @0 PSH @0 draw vraster img, x, imgy, h, u, v, u, vend POP @0 ADD @0 1 ADD# u ustep JMP m7_di_loop @m7_di_loop_end: endproc rem ================================================================== rem Clear objects. rem ================================================================== procedure M7_ClearObjects() m7_ObjCount = 0 for i = 0 to M7_MAX_OBJECTS - 1 MOV# @0 m7_Objects MOV [@0] 0 m7_ObjOrder[i] = 0 next endproc rem ================================================================== rem rem ================================================================== procedure M7_AddObject(id, img, x#, z#, y#, h#, cel, item_x, item_z) index = -1 for i = 0 to M7_MAX_OBJECTS - 1 MOV# @0 m7_Objects MOV @1 i MUL @1 11 STP# @0 @1 CMP [@0] 0 JNE m7_ao_no_obj MOV index i break @m7_ao_no_obj: next if index >= 0 if item_x >= 0 xz = item_z*m7_MapW + item_x else xz = -1 endif rem Move to index. MOV# @0 m7_Objects MOV @1 index MUL @1 11 STP# @0 @1 rem Set values. MOV [@0] id STP# @0 1 MOV [@0] img STP# @0 1 MOV# [@0] x STP# @0 1 MOV# [@0] z STP# @0 1 MOV# [@0] y STP# @0 3 MOV [@0] xz STP# @0 1 MOV# [@0] h STP# @0 2 MOV [@0] cel m7_ObjOrder[m7_ObjCount] = index ADD m7_ObjCount 1 endif endproc rem ================================================================== rem rem ================================================================== procedure M7_ModifyObject(id, img, x#, z#, y#, h#, cel) index = -1 for i = 0 to M7_MAX_OBJECTS - 1 MOV# @0 m7_Objects MOV @1 i MUL @1 11 STP# @0 @1 CMP [@0] id JNE m7_mo_no_obj MOV index i break @m7_mo_no_obj: next if index >= 0 rem Move to index. MOV# @0 m7_Objects MOV @1 index MUL @1 11 ADD @1 1 STP# @0 @1 rem Set values. MOV [@0] img STP# @0 1 MOV# [@0] x STP# @0 1 MOV# [@0] z STP# @0 1 MOV# [@0] y STP# @0 4 MOV# [@0] h STP# @0 2 MOV [@0] cel endif endproc rem ================================================================== rem rem ================================================================== procedure M7_RemoveObject(id) index = -1 for i = 0 to M7_MAX_OBJECTS - 1 MOV# @0 m7_Objects MOV @1 i MUL @1 11 STP# @0 @1 CMP [@0] id JNE m7_ro_no_obj MOV index i break @m7_ro_no_obj: next if index >= 0 xz rem Move to index. MOV# @0 m7_Objects MOV @1 index MUL @1 11 STP# @0 @1 MOV [@0] 0 STP# @0 7 MOV xz [@0] for i = 0 to M7_MAX_OBJECTS - 1 if m7_ObjOrder[i] = index for j = i to m7_ObjCount - 2 m7_ObjOrder[j] = m7_ObjOrder[j + 1] next m7_ObjCount = m7_ObjCount - 1 break endif next if xz > 0 then m7_Item[xz%m7_MapW][xz/m7_MapW] = 0 endif endproc procedure M7_RemoveObjectByIndex(index) if index >= 0 xz rem Move to index. MOV# @0 m7_Objects MOV @1 index MUL @1 11 STP# @0 @1 MOV [@0] 0 STP# @0 7 MOV xz [@0] for i = 0 to M7_MAX_OBJECTS - 1 if m7_ObjOrder[i] = index for j = i to m7_ObjCount - 2 m7_ObjOrder[j] = m7_ObjOrder[j + 1] next m7_ObjCount = m7_ObjCount - 1 break endif next if xz > 0 then m7_Item[xz%m7_MapW][xz/m7_MapW] = 0 endif endproc rem ================================================================== rem rem ================================================================== function M7_HasObject(id) index = -1 for i = 0 to M7_MAX_OBJECTS - 1 MOV# @0 m7_Objects MOV @1 i MUL @1 11 STP# @0 @1 CMP [@0] id JNE m7_ho_no_obj MOV index i break @m7_ho_no_obj: next if index >= 0 then return true return false endfunc rem ================================================================== rem Process objects before rendering. rem ================================================================== procedure M7_ProcessObjects(xpos#, zpos#, angle#) rem Calculate distance between objects and view point. dx# dz# for i = 0 to M7_MAX_OBJECTS - 1 MOV# @0 m7_Objects MOV @1 i MUL @1 11 STP# @0 @1 CMP [@0] 0 JE m7_po_d_no_obj rem dx. STP# @0 2 MOV# @1 [@0]; rem obj x. SUB# @1 xpos MUL# @1 @1 rem dy. STP# @0 1 MOV# @2 [@0]; rem obj y. SUB# @2 zpos MUL# @2 @2 ADD# @1 @2 rem d. STP# @0 6 MOV# [@0] @1 @m7_po_d_no_obj: next rem Sort the objects. proc M7_SortObjects endproc rem ================================================================== rem Sort objects. rem Yes, bubble sort is used, since the changes in the list are rem usually very small. rem ================================================================== procedure M7_SortObjects() beg = 0 endi = m7_ObjCount - 2 noswap @m7_so_loop: MOV noswap 1 MOV @5 beg @m7_so_sort: MOV @1 m7_ObjOrder STP @1 @5 PSH @1 MOV @1 [@1] MUL @1 11 ADD @1 9 MOV @2 m7_ObjOrder STP @2 @5 STP @2 1 PSH @2 MOV @2 [@2] MUL @2 11 ADD @2 9 MOV# @0 m7_Objects STP# @0 @1 MOV# @1 [@0] MOV# @0 m7_Objects STP# @0 @2 MOV# @2 [@0] CMP# @1 @2 JGE# m7_so_no_swap MOV noswap 0 POP @2 POP @1 MOV @3 [@2] MOV [@2] [@1] MOV [@1] @3 JMP m7_so_swap_done @m7_so_no_swap: POP @0 POP @0 @m7_so_swap_done: ADD @5 1 CMP @5 endi JLE m7_so_sort ADD beg 1 CMP noswap 1 JNE m7_so_loop endproc rem ================================================================== rem rem ================================================================== function M7_LoadMap[][](filename$) flags[][] open file 0, filename$ if not file(0) then return flags for i = len(filename) - 1 downto 0 if mid$(filename, i) = "/" or mid$(filename$, i) = "\" pos = i + 1 break endif next path$ = left$(filename, pos) rem Images. count = read(0) for i = 0 to count - 1 index = read(0) load image index + 1000, path + read$(0) ck = read(0) ckr = read(0) ckg = read(0) ckb = read(0) if ck then set image colorkey index + 1000, ckr, ckg, ckb next rem Objects. objects[64][4] count = read(0) for i = 0 to count - 1 index = read(0) objects[index][0] = read(0) objects[index][1] = read(0) objects[index][2] = read(0) objects[index][3] = read(0) next rem Fog. fogActive = read(0) fogR = read(0) fogG = read(0) fogB = read(0) fogZMin# = read#(0) fogZMax# = read#(0) rem Map. mapW = read(0) mapH = read(0) map[mapW][mapH][6] for i = 0 to 5 for z = 0 to mapH - 1 for x = 0 to mapW - 1 map[x][z][i] = read(0) next next next playerX = read(0) playerZ = read(0) playerAngle = read(0) free file 0 if fogActive proc M7_SetFog fogR, fogG, fogB, fogZMin, fogZMax endif proc M7_InitMap mapW, mapH WALL = 0 FLOOR = 1 CEILING = 2 OBJECT = 3 GAME_FLAG = 4 LOADER_FLAG = 5 flagCount = 0 for z = 0 to mapH - 1 for x = 0 to mapW - 1 if map[x][z][LOADER_FLAG] then flagCount = flagCount + 1 if map[x][z][FLOOR] proc M7_SetFloor x, z, map[x][z][FLOOR] + 1000 endif proc M7_SetFlag x, z, map[x][z][GAME_FLAG] if map[x][z][OBJECT] obj = map[x][z][OBJECT] rem [index][image, align, obstacle, size] img = objects[obj][0] if img and image(img + 1000) img = img + 1000 h# = float(objects[obj][3])/1000.0 proc M7_AddObject -1, img, float(x) + 0.5, float(z) + 0.5, 0.0, h, 0, x, z proc M7_SetItem x, z, map[x][z][OBJECT] endif endif next next flags[flagCount + 1][3] flags[0][0] = playerX flags[0][1] = playerZ flags[0][2] = playerAngle index = 1 for z = 0 to mapH - 1 for x = 0 to mapW - 1 if map[x][z][LOADER_FLAG] flags[index][0] = x flags[index][1] = z flags[index][2] = map[x][z][LOADER_FLAG] index = index + 1 endif next next return flags endfunc rem ================================================================== rem rem ================================================================== procedure M7_InitMap(w, h) m7_MapW = w m7_MapH = h m7_Floor[w][h] m7_Flag[w][h] m7_Item[w][h] endproc rem ================================================================== rem rem ================================================================== procedure M7_SetFog(r, g, b, zMin#, zMax#) m7_FogR = r m7_FogG = g m7_FogB = b m7_FogMin = zMin# m7_FogMax = zMax# m7_FogSpread = 255.0/(zMax - zMin) m7_MaxZ = zMax endproc rem ================================================================== rem rem ================================================================== procedure M7_SetFloor(x, z, img) m7_Floor[x][z] = img endproc rem ================================================================== rem rem ================================================================== procedure M7_SetFlag(x, z, flag) m7_Flag[x][z] = flag endproc rem ================================================================== rem rem ================================================================== procedure M7_SetItem(x, z, obj) m7_Item[x][z] = obj endproc procedure M7_RemoveItem(x, z) m7_Item[x][z] = 0 xz = z*m7_MapW + x s = M7_MAX_OBJECTS - 1 id for i = 0 to s MOV# @0 m7_Objects MOV @1 i MUL @1 11 STP# @0 @1 CMP [@0] 0 JE m7_ri_noobj MOV id [@0] STP# @0 7 CMP [@0] xz JNE m7_ri_noobj proc M7_RemoveObjectByIndex(i) break @m7_ri_noobj: next endproc rem ================================================================== rem rem ================================================================== function M7_GetFloor(x, z) return m7_Floor[x][z] - 1000 endfunc function M7_GetFloorImage(x, z) return m7_Floor[x][z] endfunc function M7_GetImage(img_index) return img_index + 1000 endfunc rem ================================================================== rem rem ================================================================== function M7_GetFlag(x, z) return m7_Flag[x][z] endfunc rem ================================================================== rem rem ================================================================== function M7_GetItem(x, z) return m7_Item[x][z] endfunc function M7_GetFlagPos[](flag) pos[] if sizeof(m7_Flag) = 0 then return pos for z = 0 to m7_MapH - 1 for x = 0 to m7_MapW - 1 if m7_Flag[x][z] = flag pos[] = [x, z] break endif next next return pos endfunc