1 /* Project 16 Source Code~
\r
2 * Copyright (C) 2012-2022 sparky4 & pngwen & andrius4669 & joncampbell123 & yakui-lover
\r
4 * This file is part of Project 16.
\r
6 * Project 16 is free software; you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation; either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * Project 16 is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with this program. If not, see <http://www.gnu.org/licenses/>, or
\r
18 * write to the Free Software Foundation, Inc., 51 Franklin Street,
\r
19 * Fifth Floor, Boston, MA 02110-1301 USA.
\r
23 #include "src/lib/16_spri.h"
\r
24 #include <hw/vga/vrl1xdrc.h>
\r
26 #define VRS_USECAMMPM
\r
28 void VRS_ReadVRS(char *filename, entity_t *enti, global_game_variables_t *gvar){ VRS_OpenVRS(filename, enti, 1, gvar); }
\r
29 void VRS_LoadVRS(char *filename, entity_t *enti, global_game_variables_t *gvar){ VRS_OpenVRS(filename, enti, 0, gvar); }
\r
30 void VRS_OpenVRS(char *filename, entity_t *enti, boolean rlsw, global_game_variables_t *gvar)
\r
32 #ifndef VRS_USECAMMPM
\r
33 vrl1_vgax_offset_t **vrl_line_offsets;
\r
35 uint16_t far *vrl_id_iter;
\r
36 uint32_t far *vrl_headers_offsets;
\r
37 struct vrl1_vgax_header far *curr_vrl;
\r
44 //TODO ++++ CA_ReadFile(filename, &gvar->ca.spribuff, gvar);
\r
45 CA_ReadFile(filename, MEMPTRCONV enti->spri.spritesheet.spribuff, gvar);
\r
48 //TODO ++++ CA_LoadFile(filename, &gvar->ca.spribuff, gvar);
\r
49 CA_LoadFile(filename, MEMPTRCONV enti->spri.spritesheet.spribuff, gvar);
\r
53 // Insert sanity cheks later
\r
54 //TODO ++++ enti->spri.spritesheet.buffer = gvar->ca.spribuff;
\r
55 enti->spri.spritesheet.buffer = enti->spri.spritesheet.spribuff; //TODO: merge these 2 vars into 1
\r
56 enti->spri.spritesheet.data_size = sizeof(enti->spri.spritesheet.buffer) - sizeof(struct vrl1_vgax_header);
\r
58 vrl_id_iter = (uint16_t far *)(enti->spri.spritesheet.buffer + enti->spri.spritesheet.vrs_hdr->offset_table[VRS_HEADER_OFFSET_SPRITE_ID_LIST]);
\r
59 while(vrl_id_iter[num_of_vrl]){
\r
63 // Allocate memory for vrl line offsets table
\r
64 #ifndef VRS_USECAMMPM
\r
65 vrl_line_offsets = malloc(sizeof(vrl1_vgax_offset_t *)*num_of_vrl);//TODO: USE MM_ CA_ AND PM_
\r
73 // MM_GetPtr(MEMPTRCONV gvar->ca.grsegs, sizeof(vrl1_vgax_offset_t *)*num_of_vrl, gvar);
\r
74 // enti->spri.spritesheet.vrl_line_offsets = (vrl1_vgax_offset_t **)gvar->ca.grsegs;
\r
75 MM_GetPtr(gvar->ca.spribuff, sizeof(vrl1_vgax_offset_t *)*num_of_vrl, gvar);
\r
76 enti->spri.spritesheet.vrl_line_offsets = (vrl1_vgax_offset_t **)(gvar->ca.spribuff);
\r
77 // MM_GetPtr(spribuff, sizeof(vrl1_vgax_offset_t *)*num_of_vrl, gvar);
\r
78 // enti->spri.spritesheet.vrl_line_offsets = (vrl1_vgax_offset_t **)spribuff;
\r
83 vrl_headers_offsets = (uint32_t far *)(enti->spri.spritesheet.buffer + enti->spri.spritesheet.vrs_hdr->offset_table[VRS_HEADER_OFFSET_VRS_LIST]);
\r
84 // Calculate line offsets for each vrl
\r
85 for(i = 0; i < num_of_vrl; i++){
\r
86 curr_vrl = (struct vrl1_vgax_header far *)(enti->spri.spritesheet.buffer + vrl_headers_offsets[i]);
\r
88 // Calc. vrl size as (next_offset - curr_offset)
\r
89 if (i != num_of_vrl - 1){
\r
90 vrl_size = vrl_headers_offsets[i+1] - vrl_headers_offsets[i] - sizeof(struct vrl1_vgax_header);
\r
92 // If it's the last vrl, size is (next_vrs_struct_offset - curr_offset)
\r
94 vrl_size = enti->spri.spritesheet.vrs_hdr->offset_table[VRS_HEADER_OFFSET_SPRITE_ID_LIST] - vrl_headers_offsets[i] - sizeof(struct vrl1_vgax_header);
\r
96 #ifndef VRS_USECAMMPM
\r
97 vrl_line_offsets[i] = vrl1_vgax_genlineoffsets(curr_vrl, (byte *)curr_vrl + sizeof(struct vrl1_vgax_header), vrl_size);
\r
99 enti->spri.spritesheet.vrl_line_offsets[i] = vrl1_vgax_genlineoffsets((struct vrl1_vgax_header *)curr_vrl, (byte *)curr_vrl + sizeof(struct vrl1_vgax_header), vrl_size);
\r
102 #ifndef VRS_USECAMMPM
\r
103 enti->spri.spritesheet.vrl_line_offsets = vrl_line_offsets;
\r
105 // printf("VRS_OpenVRS\n");
\r
106 // printf(" vrl_size=%lu\n\n",vrl_size);
\r
111 void VRS_ReadVRL(char *filename, entity_t *enti, global_game_variables_t *gvar){ VRS_OpenVRL(filename, enti, 1, gvar); }
\r
112 void VRS_LoadVRL(char *filename, entity_t *enti, global_game_variables_t *gvar){ VRS_OpenVRL(filename, enti, 0, gvar); }
\r
113 void VRS_OpenVRL(char *filename, entity_t *enti, boolean rlsw, global_game_variables_t *gvar)
\r
115 #ifndef VRL_USECAMMPM
\r
116 vrl1_vgax_offset_t *line_offsets;
\r
118 // uint32_t far *vrl_headers_offsets;
\r
119 struct vrl1_vgax_header far *curr_vrl;
\r
124 CA_ReadFile(filename, &enti->spri.spritesheet.spribuff, gvar);
\r
127 CA_LoadFile(filename, &enti->spri.spritesheet.spribuff, gvar);
\r
131 // Insert sanity cheks later
\r
132 enti->spri.sprite_vrl_cont.buffer = enti->spri.spritesheet.spribuff;
\r
133 enti->spri.sprite_vrl_cont.data_size = sizeof(enti->spri.spritesheet.buffer) - sizeof(struct vrl1_vgax_header);
\r
135 // Allocate memory for vrl line offsets table
\r
136 #ifndef VRL_USECAMMPM
\r
137 line_offsets = malloc(sizeof(vrl1_vgax_offset_t *));//TODO: USE MM_ CA_ AND PM_
\r
139 MM_GetPtr(MEMPTRCONV gvar->ca.grsegs[0], sizeof(vrl1_vgax_offset_t *), gvar);
\r
140 enti->spri.sprite_vrl_cont.line_offsets = (vrl1_vgax_offset_t *)gvar->ca.grsegs[0];
\r
143 //vrl_headers_offsets = (uint32_t far *)(enti->spri.sprite_vrl_cont.buffer + enti->spri.sprite_vrl_cont.vrs_hdr->offset_table[VRL_HEADER_OFFSET_VRL_LIST]);
\r
144 // Calculate line offsets for each vrl
\r
145 curr_vrl = (struct vrl1_vgax_header far *)(enti->spri.sprite_vrl_cont.buffer);// + vrl_headers_offsets);
\r
147 #ifndef VRL_USECAMMPM
\r
148 line_offsets = vrl1_vgax_genlineoffsets(curr_vrl, (byte *)curr_vrl + sizeof(struct vrl1_vgax_header), sizeof(enti->spri.spritesheet.buffer));
\r
150 enti->spri.sprite_vrl_cont.line_offsets = vrl1_vgax_genlineoffsets(curr_vrl, (byte *)curr_vrl + sizeof(struct vrl1_vgax_header), sizeof(enti->spri.spritesheet.buffer));
\r
153 #ifndef VRL_USECAMMPM
\r
154 enti->spri.sprite_vrl_cont.line_offsets = line_offsets;
\r
156 printf("VRS_OpenVRL\n");
\r
157 printf(" vrl_size=%lu\n\n",sizeof(enti->spri.spritesheet.buffer));
\r
162 // Seek and return a specified .vrl blob from .vrs blob in far memory
\r
163 int get_vrl_by_id(struct vrs_container far *vrs_cont, uint16_t id, struct vrl_container *vrl_cont){
\r
165 uint32_t far *vrl_offs_list;
\r
168 // If id is invalid, return -1
\r
170 // Probably add an error message?
\r
174 // Get id list from .vrs blob (base + offset)
\r
175 ids = (uint16_t far*)(vrs_cont->buffer +
\r
176 vrs_cont->vrs_hdr->offset_table[VRS_HEADER_OFFSET_SPRITE_ID_LIST]);
\r
178 // Loop through the id list until we found the right one or hit the end of the list
\r
179 // Counter is keeping track of the offset(in ids/vrl blobs)
\r
180 while(ids[counter] != id && ids[counter]){
\r
183 // Return -2 if we couldn't find the requested id
\r
189 // Get vrl offsets list from .vrs blob (base + offset)
\r
190 vrl_offs_list = (uint32_t far *)(vrs_cont->buffer +
\r
191 vrs_cont->vrs_hdr->offset_table[VRS_HEADER_OFFSET_VRS_LIST]);
\r
193 // Get vrl_header from .vrs (base + offset from vrl_list)
\r
194 // Counter is number of vrls to skip (ids and vrls are aligned according to the .vrs specification)
\r
195 vrl_cont->vrl_header = (struct vrl1_vgax_header far *)(vrs_cont->buffer + vrl_offs_list[counter]);
\r
197 // Get .vrl size by integer arithmetics (next vrl offset - current vrl offset)
\r
198 if(ids[counter+1]){
\r
199 vrl_cont->data_size = vrl_offs_list[counter+1] - vrl_offs_list[counter] - sizeof(struct vrl1_vgax_header);
\r
201 // If we are retriving the last vrl, size is ids_list offset - current vrl offset, as next vrl offs is 0
\r
203 vrl_cont->data_size = vrs_cont->vrs_hdr->offset_table[VRS_HEADER_OFFSET_SPRITE_ID_LIST] - vrl_offs_list[counter] - sizeof(struct vrl1_vgax_header);
\r
206 // Retrive line offsets form .vrs
\r
207 vrl_cont->line_offsets = vrs_cont->vrl_line_offsets[counter];
\r
212 //void draw_vrl1_vgax_modex_strip(unsigned char far *draw,unsigned char far *s);
\r
214 //===========================================================================
\r
216 //#define NEWVRSDRAWFUN
\r
217 void DrawVRL (unsigned int x,unsigned int y,struct vrl1_vgax_header *hdr,vrl1_vgax_offset_t *lineoffs/*array hdr->width long*/,unsigned char *data,unsigned int datasz) {
\r
218 unsigned char far *draw;
\r
219 unsigned int vram_offset = (y * vga_state.vga_draw_stride) + (x >> 2),sx;
\r
220 unsigned int vramlimit = vga_state.vga_draw_stride_limit;
\r
221 unsigned char vga_plane = (x & 3);
\r
224 // byte outputvars[72][128];
\r
225 word a;//,by,bxmax,bymax;
\r
227 printf("DrawVRL:\n");
\r
229 /* draw one by one */
\r
230 for (sx=0;sx < hdr->width;sx++) {
\r
231 draw = vga_state.vga_graphics_ram + vram_offset;
\r
232 vga_write_sequencer(0x02/*map mask*/,1 << vga_plane);
\r
233 s = data + lineoffs[sx];
\r
234 draw_vrl1_vgax_modex_strip(draw,s);
\r
237 for(a=0;a<hdr->height;a++)//hdr->width*
\r
239 // if((*(s+a)==0x0) && (*(s+(a+1))==0x20) && (*(s+(a+2))==0xff)) a+=2;
\r
241 // if (!(a%4) && a ) printf("\n");
\r
242 // sprintf(outputvars[sx][by], "%02x", *(s+a));
\r
243 printf("[%02u] %u\n", a, *(s+a));
\r
247 /* end of a vertical strip. next line? */
\r
248 if ((++vga_plane) == 4) {
\r
249 if (--vramlimit == 0) break;
\r
255 bxmax = sx; bymax = by;
\r
256 for(by=0;by<bymax;by++)
\r
258 for(sx=0;sx<bxmax;sx++)
\r
260 // if (!(sx%hdr->width) && sx ) printf("\n ");
\r
261 printf("%02x ", outputvars[sx][by]);
\r
268 //===========================================================================
\r
270 char* get_curr_anim_name(struct sprite *spri)
\r
272 // Retrive animation name list
\r
273 struct vrs_header far *vrs = spri->spritesheet.vrs_hdr;
\r
274 uint32_t far *anim_names_offsets = (uint32_t far *)
\r
276 vrs->offset_table[VRS_HEADER_OFFSET_ANIMATION_NAME_LIST]);
\r
278 return (char *)(vrs + anim_names_offsets[spri->curr_anim]);
\r
281 void init_anim(struct sprite *spri, int anim_index)
\r
283 struct vrs_header far *vrs = spri->spritesheet.vrs_hdr;
\r
284 uint32_t far *anim_lists_offsets = (uint32_t far *)
\r
286 vrs->offset_table[VRS_HEADER_OFFSET_ANIMATION_LIST]);
\r
287 struct vrs_animation_list_entry_t far *anim_list = (struct vrs_animation_list_entry_t far *)
\r
289 anim_lists_offsets[anim_index]);
\r
291 // Upon new animation, start from the first sprite in it
\r
292 spri->curr_anim = anim_index;
\r
293 spri->curr_anim_spri = 0;
\r
294 spri->curr_spri_id = anim_list[0].sprite_id;
\r
295 spri->delay = anim_list[0].delay;
\r
297 spri->curr_anim_list = (struct vrs_animation_list_entry_t *)anim_list;
\r
300 int set_anim_by_id(struct sprite *spri, int anim_id)
\r
302 int new_anim_index = 0;
\r
304 struct vrs_header far *vrs = spri->spritesheet.vrs_hdr;
\r
305 // Retruve animation ids list
\r
306 uint16_t far *anim_ids = (uint16_t far *)
\r
308 vrs->offset_table[VRS_HEADER_OFFSET_ANIMATION_ID_LIST]);
\r
310 // Loop through animation id untill match or end of list
\r
311 while(iter_id = anim_ids[new_anim_index])
\r
313 // Return on successful match
\r
314 if (iter_id == anim_id)
\r
316 init_anim(spri, new_anim_index);
\r
324 void print_anim_ids(struct sprite *spri)
\r
326 int new_anim_index = 0;
\r
328 struct vrs_header far *vrs = spri->spritesheet.vrs_hdr;
\r
329 // Retruve animation ids list
\r
330 uint16_t far *anim_ids = (uint16_t far *)
\r
332 vrs->offset_table[VRS_HEADER_OFFSET_ANIMATION_ID_LIST]);
\r
334 if(!anim_ids[new_anim_index])
\r
336 // Loop through animation id untill match or end of list
\r
337 while(iter_id = anim_ids[new_anim_index])
\r
339 printf("s%d ", iter_id);
\r
344 void animate_spri(entity_t *enti, video_t *video)
\r
346 #define INC_PER_FRAME if(enti->q&1) enti->persist_aniframe++; if(enti->persist_aniframe>4) enti->persist_aniframe = 1;
\r
347 unsigned int i,o,o2; int j;
\r
349 VGA_RAM_PTR omemptr = (VGA_RAM_PTR)video->page[0].data;// save original mem ptr
\r
355 // Depending on delay, update indices
\r
356 //#define FRAME1 modexDrawSpriteRegion(pip[(pip->video->p)].page, x, y, 48, player[pn].enti.dire, 24, 32, PLAYERBMPDATAPTR);
\r
357 //#define FRAME2 modexDrawSpriteRegion(pip[(pip->video->p)].page, x, y, 24, player[pn].enti.dire, 24, 32, PLAYERBMPDATAPTR); stand
\r
358 //#define FRAME3 modexDrawSpriteRegion(pip[(pip->video->p)].page, x, y, 0, player[pn].enti.dire, 24, 32, PLAYERBMPDATAPTR);
\r
359 //#define FRAME4 modexDrawSpriteRegion(pip[(pip->video->p)].page, x, y, 24, player[pn].enti.dire, 24, 32, PLAYERBMPDATAPTR); stand
\r
361 // copy active display (0) to offscreen buffer (0x4000)
\r
362 /*vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = vga_state.vga_stride;
\r
363 vga_setup_wm1_block_copy();
\r
364 vga_wm1_mem_block_copy(copy_ofs, display_ofs, vga_state.vga_stride * vga_state.vga_height);
\r
365 vga_restore_rm0wm0();*/
\r
367 switch(enti->spri.delay)
\r
369 // Delay = 0 means that sprite should loop. Nothing to change here
\r
373 // Delay = 1 means that on next time unit sprite should be changed
\r
376 enti->spri.curr_anim_spri++;
\r
378 // If we hit the end of an animation sequence, restart it
\r
379 if(!( enti->spri.curr_spri_id = enti->spri.curr_anim_list[enti->spri.curr_anim_spri].sprite_id)){
\r
380 enti->spri.curr_anim_spri = 0;
\r
381 enti->spri.curr_spri_id = enti->spri.curr_anim_list[enti->spri.curr_anim_spri].sprite_id;
\r
383 enti->spri.delay = enti->spri.curr_anim_list[enti->spri.curr_anim_spri].delay;
\r
385 // Delay > 1 means that we should not change sprite yet. Decrease delay
\r
387 enti->spri.delay--;
\r
396 j = get_vrl_by_id(&enti->spri.spritesheet, enti->spri.curr_spri_id, &enti->spri.sprite_vrl_cont);
\r
399 //Quit (gv, "Error retriving required sprite");
\r
403 // render box bounds. y does not need modification, but x and width must be multiple of 4
\r
404 if(!video->vga_state.rss)
\r
406 if (x >= enti->overdraww) rx = (x - enti->overdraww) & (~3);
\r
407 else rx = -(video->page[0].dx);
\r
408 if (y >= enti->overdrawh) ry = (y - enti->overdrawh);
\r
409 else ry = -(video->page[0].dy);
\r
410 h = enti->spri.sprite_vrl_cont.vrl_header->height + enti->overdrawh + y - ry;
\r
411 w = (x + enti->spri.sprite_vrl_cont.vrl_header->width + (enti->overdraww*2) + 3 - rx) & (~3) - enti->overdraww;//round up
\r
412 if ((rx+w) > video->page[0].width) w = video->page[0].width-rx;
\r
413 if ((ry+h) > video->page[0].height) h = video->page[0].height-ry;
\r
415 if(!video->vga_state.bgps){
\r
416 // block copy pattern to where we will draw the sprite
\r
417 vga_setup_wm1_block_copy();
\r
418 o2 = video->ofs.offscreen_ofs;
\r
419 o = video->ofs.pattern_ofs + (ry * video->page[0].stridew) + (rx >> 2); // source offscreen
\r
420 for (i=0;i < h;i++,o += video->page[0].stridew,o2 += (w >> 2)) vga_wm1_mem_block_copy(o2,o,w >> 2);
\r
422 // must restore Write Mode 0/Read Mode 0 for this code to continue drawing normally
\r
423 vga_restore_rm0wm0();
\r
425 // replace VGA stride with our own and mem ptr. then sprite rendering at this stage is just (0,0)
\r
426 vga_state.vga_draw_stride = w >> 2;
\r
427 vga_state.vga_graphics_ram = omemptr + video->ofs.offscreen_ofs;
\r
428 }else{ rx=ry=w=h=0; vga_state.vga_graphics_ram = (VGA_RAM_PTR)video->page[0].data; }
\r
429 vga_state.vga_draw_stride_limit = (video->page[0].width + 3 - x) >> 2;//round up
\r
431 // then the sprite. note modding ram ptr means we just draw to (x&3,0)
\r
433 modexClearRegion(&video->page[0], x, y, 16, 32, 1);
\r
435 #ifndef NEWVRSDRAWFUN
\r
436 draw_vrl1_vgax_modex
\r
443 enti->spri.sprite_vrl_cont.vrl_header,
\r
444 enti->spri.sprite_vrl_cont.line_offsets,
\r
445 enti->spri.sprite_vrl_cont.buffer + sizeof(struct vrl1_vgax_header),
\r
446 enti->spri.sprite_vrl_cont.data_size
\r
449 #ifdef __DEBUG_SPRI__
\r
450 // if(ggvv->player[0].enti.q<5)
\r
451 if(dbg_delayanimation)
\r
455 // static struct glob_game_vars *ggvv; IN_Ack(ggvv);
\r
456 // { while(!IN_KeyDown(sc_Space)/* && !IN_KeyDown(sc_Escape)*/){} delay(250); }
\r
460 if(!video->vga_state.rss)
\r
463 vga_state.vga_graphics_ram = omemptr;
\r
465 if(!video->vga_state.bgps){
\r
466 // block copy to visible RAM from offscreen
\r
467 vga_setup_wm1_block_copy();
\r
468 o = video->ofs.offscreen_ofs; // source offscreen
\r
469 o2 = (ry * video->page[0].stridew) + (rx >> 2); // dest visible (original stride)
\r
470 for (i=0;i < h;i++,o += vga_state.vga_draw_stride,o2 += video->page[0].stridew) vga_wm1_mem_block_copy(o2,o,w >> 2);
\r
471 // must restore Write Mode 0/Read Mode 0 for this code to continue drawing normally
\r
472 vga_restore_rm0wm0();
\r
476 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = video->page[0].stridew;
\r
478 vga_state.vga_graphics_ram = video->vga_state.omemptr;
\r