Stage drawing routine.
[cantaveria.git] / graphics.c
blob01d1134b0d82df1131da71d8609d3a36b81510e9
1 /* graphics */
3 /* these are graphics routines but they rely on the backend.c for actual
4 drawing commands. */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdarg.h>
10 #include <math.h>
12 #include "util.h"
13 #include "backend.h"
14 #include "graphics.h"
15 #include "loader.h"
17 #include "game.h"
20 /* graphics data */
21 sprite* sprites[MAX_SPRITES];
22 int sprite_count = 0;
24 animation* animations[MAX_ANIMATIONS];
25 int anim_count = 0;
27 int minifont_gfx = 0;
31 int stage_enabled = 0;
35 struct {
36 int x, y;
37 } camera;
40 void graphics_init(){
41 minifont_gfx = load_gfx("smallfont.tga");
42 for(int i=0; i<MAX_ANIMATIONS; i++){
43 animations[i] = NULL;
48 /* drawing */
50 void draw_sprite(sprite* spr){
51 int x = spr->x - 0;
52 int y = spr->y - 0;
53 int W = spr->w;
54 int H = spr->h;
55 int X = spr->frame.x;
56 int Y = spr->frame.y;
57 int g = spr->gfxid;
58 draw_gfx(g, x, y, X, Y, W, H);
62 void draw_screen(zone* z, int si, int sj){
63 struct screen* scr = z->screens+si+z->w*sj;
64 int G = z->tileset;
65 int x = si*20*16 - camera.x;
66 int y = sj*15*16 - camera.y;
68 for(int j=0; j < 15; j++){
69 for(int i=0; i < 20; i++){
70 if(x > 320 || y > 240 || x < -16 || y < -16) continue;
71 int id = scr->tiles[i][j].id;
72 if(id != 0){
73 int X = id&7;
74 int Y = id>>3;
75 draw_gfx(G, x, y, X, Y, 16, 16);
77 else{
78 //draw background
80 x += 16;
82 x -= 320;
83 y += 16;
85 }*/
95 void draw_small_text(char* str, int x, int y){
96 for(char* c=str; *c; c++){
97 int X = *c & 0x0f;
98 int Y = *c >> 4;
99 draw_gfx(minifont_gfx, x, y, X*4, Y*9, 3, 8);
100 x+=4;
106 void printf_small(int x, int y, char* format, ...){
107 char str[128];
108 va_list ap;
109 va_start(ap, format);
110 vsnprintf(str, 128, format, ap);
111 va_end(ap);
112 str[127]='\0';
113 draw_small_text(str, x, y);
119 void draw_screen(zone* z, int si, int sj){
121 struct screen* scr = *(z->screens+si+z->w*sj);
122 int G = z->tileset_gfx;
123 int x = si*20*16 - camera.x;
124 int y = sj*15*16 - camera.y;
126 for(int j=0; j < 15; j++){
127 for(int i=0; i < 20; i++){
128 if(x > 320 || y > 240 || x < -16 || y < -16) continue;
129 int id = scr->tiles[i][j];
130 if(id != 0){
131 int X = (id&0xf)<<4;
132 int Y = (id>>4)<<4;
133 draw_gfx(G, x, y, X, Y, 16, 16);
135 else{
136 //draw background
138 x += 16;
140 x -= 320;
141 y += 16;
146 void draw_stage(){
147 draw_screen(game.zones[0], 0, 0);
150 void draw(){
152 if(stage_enabled){
153 draw_stage();
156 for(int i=0; i<sprite_count; i++){
157 draw_sprite(sprites[i]);
160 printf_small(1,1,"testing stage");
162 update_video();
163 clear_video();
169 void point_camera(int x, int y){
170 camera.x = x;
171 camera.y = y;
176 void animate_sprites(){
177 for(int i=0; i<sprite_count; i++){
178 sprite* spr = sprites[i];
180 spr->frame_counter += dt;
181 animation* ani = animations[spr->anim];
184 while(spr->frame_counter > ani->frame_lens[spr->current_frame]){
185 spr->frame_counter -= ani->frame_lens[spr->current_frame];
186 spr->current_frame++;
187 if(spr->current_frame == ani->frame_count){
188 spr->current_frame = 0;
190 spr->frame = ani->frames[spr->current_frame];
193 if(spr->update) spr->update(spr, spr->userdata);
201 int load_sprite(char* filename, int id){
202 printf("loading %s\n",filename);
204 char path[1024] = "sprites/";
205 strncat(path, filename, 1023 - strlen(filename));
207 reader* rd = loader_open(path);
208 if(!rd){
209 return -1;
212 animation* ani = xmalloc(sizeof(animation));
214 char str[256];
215 int w, h;
216 int frame_count;
217 int loop_mode;
219 loader_scanline(rd,"%256s",str);
220 loader_scanline(rd,"%d %d %d %d",&w,&h,&loop_mode,&frame_count);
222 ani->frame_lens = xmalloc(frame_count*sizeof(short));
223 ani->frames = xmalloc(frame_count*sizeof(struct frame));
224 ani->frame_count = frame_count;
226 int g = load_gfx(str);
227 if(g < 0)
228 return -1;
230 ani->gfxid = g;
232 //int W = gfx[g].w;
233 //int H = gfx[g].h;
234 int W = gfx_width(g);
235 int H = gfx_height(g);
236 ani->w = w;
237 ani->h = h;
239 for(int i=0; i < frame_count; i++){
240 int l, x, y;
241 loader_scanline(rd, "%d %d %d", &l, &x, &y);
242 ani->frame_lens[i] = l;
243 ani->frames[i].x = x;
244 ani->frames[i].y = y;
245 ani->frames[i].x0 = ((double)x)/W;
246 ani->frames[i].y0 = ((double)y)/H;
247 ani->frames[i].x1 = ((double)(x+w))/W;
248 ani->frames[i].y1 = ((double)(y+h))/W;
251 loader_close(rd);
252 animations[id] = ani;
253 return 0;
259 /********************/
260 /* graphics control */
261 /********************/
263 sprite* enable_sprite(int sprnum){
264 if(!animations[sprnum]){
265 fatal_error("enable_sprite: you just tried to enable sprite with type %d, which does not exist\n",sprnum);
267 if(sprite_count == MAX_SPRITES){
268 /* need a priority based way to create important sprites if full */
269 return NULL;
271 sprite* spr = xmalloc(sizeof(sprite));
272 animation* ani = animations[sprnum];
274 spr->number = sprite_count;
275 spr->frame_counter = 0;
276 spr->current_frame = 0;
277 spr->frame = ani->frames[0];
278 spr->gfxid = ani->gfxid;
279 spr->anim = sprnum;
280 spr->x = 0;
281 spr->y = 0;
282 spr->w = ani->w;
283 spr->h = ani->h;
284 spr->vx = 0;
285 spr->vy = 0;
286 spr->update = NULL;
287 spr->userdata = NULL;
289 sprites[sprite_count++] = spr;
290 return spr;
293 void disable_sprite(sprite* spr){
294 sprite* tmp = sprites[spr->number];
295 sprites[spr->number] = sprites[sprite_count--];
296 free(tmp);
299 sprite* copy_sprite(sprite* spr){
300 if(sprite_count == MAX_SPRITES){
301 /* need way to make important sprites when full */
302 return NULL;
304 sprite* copy = xmalloc(sizeof(sprite));
305 *copy = *spr;
306 sprites[sprite_count++] = copy;
307 return copy;
312 void enable_stage(int yn){
313 stage_enabled = yn;