convert line ends
[canaan.git] / prj / cam / src / engfeat / inv_rend.c
blob1a6a9f30e062cd7fb8a018e6f472d3856034b59e
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/engfeat/inv_rend.c,v 1.47 2000/02/19 13:15:07 toml Exp $
7 // code to draw the current inventory object
8 // more generally, code to support the issue of rendering models to various canvases
9 // caching how they look, and so on
11 // massively in progress, particularly:
12 // do we want to allow hand draw models as well for things which look goofy
13 // really need to mip map all this
14 // do we want a way to have a "current" one which rotates somehow
16 #include <g2.h>
17 #include <font.h>
18 #include <r3d.h>
19 #include <md.h>
20 #include <mdutil.h>
21 #include <matrix.h>
22 #include <mlight.h>
23 #include <string.h>
24 #include <lgd3d.h>
25 #include <scrnman.h>
27 #include <mprintf.h>
28 #include <appagg.h>
29 #include <cfgdbg.h>
31 #include <wrobj.h>
32 #include <objmodel.h>
33 #include <objshape.h>
35 #include <property.h>
36 #include <invrndpr.h>
37 #include <propbase.h>
39 #include <scrnman.h>
40 #include <storeapi.h>
41 #include <resapi.h>
42 #include <imgrstyp.h>
43 #include <palrstyp.h>
44 #include <palmgr.h>
46 #include <config.h>
48 #include <mnumprop.h>
49 #include <inv_rend.h>
50 #include <memall.h>
51 #include <dbmem.h> // must be last header!
53 // internal flag bits, public ones are in inv_rend.h
54 #define INVREND_BITMAP (1<<8)
55 #define INVREND_MODEL (1<<9)
56 #define INVREND_CACHEVALID (1<<10) // currently unsupported
57 #define INVREND_IN_QUEUE (1<<11)
58 #define INVREND_FREE_ON_RENDER (1<<12)
60 #define INVREND_HARDWARE (INVREND_HARDWARE_QUEUE|INVREND_HARDWARE_IMMEDIATE)
61 #define INVREND_TYPE (INVREND_BITMAP|INVREND_MODEL)
63 // so we can flag having no model info
64 #define INV_NO_MODEL (-1)
67 // internal structure, we dont expose details of this
68 struct _invRendState {
69 struct sInvRendView;
70 ObjID obj_id; // obj_id for us
71 int model_idx; // what model idx i have
72 int bitmappalnum; //palette location, if a bitmap resource
73 IRes *pBMRes; // Bitmap resource, if not a model
74 short flags; // any flags
75 grs_canvas *back_buffer; // app managed back buffer; if NULL, render to vis_buffer
76 grs_canvas vis_buffer; // visible buffer; sub canvas of screen canvas specified by draw_rect.
77 Rect draw_rect;
78 sInvRenderType rendtype;
81 // the override how i draw properties
82 static IInvRenderProperty* gpInvRendProp = NULL;
84 // The path for finding bitmaps
85 #define BITMAP_PATH "obj\\"
86 static ISearchPath *gpInvRendBitmapPath = NULL;
88 static float gRenderZoom = 4.0;
90 /////////////////
91 // actual renderer
93 EXTERN BOOL g_lgd3d;
94 EXTERN BOOL g_null_raster;
95 int g_inv_bcolor = -1;
98 static mls_multi_light lights[] =
100 #ifdef RGB_LIGHTING //zb :
101 // primary, ~30 degrees clockwise from x axis, 100+ feet away
102 { { 85.0, 50.0, 20.0 }, { 0.0 }, { 100.0, 100.0, 100.0 }, },
103 // secondary, behind object but not opposite
104 { { -50.0, -85.0, -10.0 }, { 0.0 }, { 30.0, 30.0, 30.0 }, },
105 #else //zb
107 // primary, ~30 degrees clockwise from x axis, 100+ feet away
108 { { 85.0, 50.0, 20.0 }, { 0.0 }, 100.0, },
109 // secondary, behind object but not opposite
110 { { -50.0, -85.0, -10.0 }, { 0.0 }, 30.0, },
111 #endif //zb
114 //zb:
115 static void start_ir_stride(void)
117 #ifdef RGB_LIGHTING
118 if( g_lgd3d )
120 r3d_glob.cur_stride = sizeof(g2s_point); // for
121 mdd_rgb_lighting = TRUE;
122 mld_multi_rgb = TRUE;
123 return;
125 mld_multi_rgb = FALSE;
126 #endif
127 mdd_rgb_lighting = FALSE;
128 r3d_glob.cur_stride = sizeof(r3s_point);
131 //zb:
132 static void end_ir_stride(void)
134 r3d_glob.cur_stride = sizeof(r3s_point);
135 mld_multi_rgb = FALSE;
138 #define NUM_LIGHTS (sizeof(lights)/sizeof(lights[0]))
140 // if there is a back buffer, render there, else render to vis_buffer
141 static void render_single_obj(invRendState *us, BOOL bClearZBuffer)
143 int clr_color=g_inv_bcolor;
144 mxs_real zoom = gRenderZoom;
146 #ifdef DEEPC
147 #ifndef SHIP
148 // Objects with 32-bit textures would kill us in software rendering.
149 if (!g_lgd3d)
150 return;
151 #endif
152 #endif
154 if (us->back_buffer)
155 gr_push_canvas(us->back_buffer);
156 else
157 gr_push_canvas(&us->vis_buffer);
159 if ((g_lgd3d) && (!g_null_raster))
161 if ((us->flags & INVREND_HARDWARE)&&(us->flags & INVREND_MODEL))
163 // clear the zbuffer for HW
164 lgd3d_set_offsets(us->draw_rect.ul.x, us->draw_rect.ul.y);
165 if( bClearZBuffer )
166 lgd3d_clear_z_rect(0, 0, grd_bm.w, grd_bm.h);
170 if ((us->flags & INVREND_CLEAR) && (clr_color == -1))
171 clr_color = 0;
173 if (clr_color!=-1)
174 gr_clear(clr_color);
176 if (us->flags&INVREND_MODEL)
178 // first, pick camera location correctly
179 mxs_vector cam_base={0,0,0};
180 mxs_vector cam_loc, obj_loc={0,0,0};
181 mxs_angvec cam_ang;
182 mxs_matrix cam_mat;
183 mds_model *m;
184 mls_multi_light tmplights[NUM_LIGHTS];
186 // check that it's actually an md model
187 // MAHK 7/30: this is basically here to catch mesh models
188 if(objmodelGetModelType(us->model_idx)!=OM_TYPE_MD)
190 ConfigSpew("InvrendSpew",("render_single_obj: unable to render non-md inventory item\n"));
191 gr_pop_canvas();
192 return;
196 cam_base.el[0]=us->cam_dist*zoom;
197 if (us->flags&INVREND_DISTANT)
198 cam_base.el[0]*=2.00;
200 mx_ang2mat(&cam_mat,&us->off_ang);
201 mx_mat_mul_vec(&cam_loc,&cam_mat,&cam_base);
202 cam_ang=us->off_ang;
203 cam_ang.el[2]+=0x8000; // does this work?
204 cam_ang.el[1]=-cam_ang.el[1];
206 // orbit the lights with the camera
208 int i;
209 for (i = 0; i < NUM_LIGHTS; i++)
211 #ifdef RGB_LIGHTING
212 tmplights[i].bright.x = us->lighting*lights[i].bright.x;
213 tmplights[i].bright.y = us->lighting*lights[i].bright.y;
214 tmplights[i].bright.z = us->lighting*lights[i].bright.z;
215 #else
216 tmplights[i].bright.x = us->lighting*lights[i].bright.x;
217 tmplights[i].bright.y = us->lighting*lights[i].bright.y;
218 tmplights[i].bright.z = us->lighting*lights[i].bright.z;
219 #endif
220 mx_mat_mul_vec(&tmplights[i].loc,&cam_mat,&lights[i].loc);
224 // now start up the 3d
225 r3_start_frame();
226 r3_set_zoom(zoom);
228 r3_set_view_angles(&cam_loc,&cam_ang,R3_DEFANG);
230 // @TODO: THIS NEEDS TO BECOME A CALL TO RENDOBJ, OR DOES IT?
231 r3_start_object(&obj_loc);
233 // @TODO: would like to try to do the DIMMED control
234 md_set_render_light(TRUE);
235 // md_set_render_light(FALSE);
237 // render the darn thing
238 if ((m=(mds_model *)objmodelGetModel(us->model_idx))!=NULL)
239 { // get real joint parms, colors?
240 extern mds_parm *getRendParms(ObjID obj, mds_model *m);
241 mds_parm *parms=NULL; // this should all be in a function call!
243 if (m->parms)
244 parms=getRendParms(us->obj_id,m);
245 md_mat_colors_set(m);
246 mld_multi_hilight = 0;
247 mld_multi_ambient = 0.1;
248 mld_multi_ambient_only = FALSE;
249 mld_multi_unlit = FALSE;
250 ml_multi_set_lights_for_object(NUM_LIGHTS,tmplights,&obj_loc,2.0);
251 objmodelSetupMdTextures(us->obj_id,m,us->model_idx);
252 // wsf: why was md_fancy_render_model being called twice?
253 // md_fancy_render_model(m,parms);
255 start_ir_stride();//zb
256 md_fancy_render_model(m,parms);
257 end_ir_stride(); //zb
260 r3_end_object(); // and close down the frame
261 r3_end_frame();
263 else if (us->flags&INVREND_BITMAP)
265 grs_bitmap *bm = IRes_Lock(us->pBMRes);
266 bm->align = us->bitmappalnum;
267 gr_bitmap(bm,0,0);
268 IRes_Unlock(us->pBMRes);
270 else
271 Warning(("No modelNum for inv obj %d\n",us->obj_id));
273 gr_pop_canvas();
276 ////////////////
277 // cache/canvas controller
278 static void _invInitCamera(invRendState *us)
280 if (us->flags&INVREND_MODEL)
282 mds_model *m;
283 us->off_ang.el[0]=us->off_ang.el[2]=0;
284 us->off_ang.el[1]=0xf000;
285 us->cam_dist=3.0; // hopefully this gets fixed below
286 if ((m=(mds_model *)objmodelGetModel(us->model_idx))!=NULL)
287 us->cam_dist=m->radius+0.7;
288 } // set scale factor here, i guess
291 static void _invGetModelIdx(invRendState *us)
293 int new_idx;
295 us->model_idx=INV_NO_MODEL; // so we have a value if nothing works
296 us->bitmappalnum=0; // so if we aren't a bitmap, this is set
297 // correctly
299 switch (us->rendtype.type)
302 case kInvRenderModel:
303 if ((new_idx=objmodelLoadModel(us->rendtype.resource.text))!=MIDX_INVALID)
305 us->model_idx=new_idx;
306 objmodelIncRef(us->model_idx);
307 us->flags|=INVREND_MODEL;
309 break;
311 case kInvRenderBitmap:
313 IResMan *pResMan = AppGetObj(IResMan);
314 IRes *new_pRes = IResMan_Bind(pResMan,
315 us->rendtype.resource.text,
316 RESTYPE_IMAGE,
317 gpInvRendBitmapPath,
318 NULL,
320 if (new_pRes)
322 IRes *pPallRes = IResMan_Retype(pResMan,
323 new_pRes,
324 RESTYPE_PALETTE,
328 us->pBMRes=new_pRes; //ok, so we send this resource over to "us"
329 //presumably it gets released later.
330 us->flags|=INVREND_BITMAP;
334 if (pPallRes)
336 void *pPall = IRes_Lock(pPallRes);
337 if (us->bitmappalnum==0)
339 us->bitmappalnum = palmgr_alloc_pal(pPall);
341 IRes_Unlock(pPallRes);
342 IRes_Drop(pPallRes);
343 SafeRelease(pPallRes);
346 SafeRelease(pResMan);
347 break;
350 case kInvRenderDefault:
351 if (ObjGetModelNumber(us->obj_id,&us->model_idx))
352 us->flags|=INVREND_MODEL; // just use the default world model for us
353 break;
355 if ((us->model_idx==INV_NO_MODEL) && (!us->pBMRes))
356 Warning(("No Inventory Model IDX for %d",us->obj_id));
359 static void _invFreeModelIdx(invRendState *us)
362 switch (us->rendtype.type)
364 case kInvRenderModel:
365 if (us->model_idx!=INV_NO_MODEL)
366 objmodelDecRef(us->model_idx);
367 break;
368 case kInvRenderBitmap:
369 if (us->bitmappalnum!=0)
371 palmgr_release_slot(us->bitmappalnum);
372 us->bitmappalnum=0;
374 if (us->pBMRes)
375 SafeRelease(us->pBMRes);
376 break;
380 static void invrend_init_state(invRendState* us, int flags, const Rect *r, grs_canvas *draw_cnv)
382 grs_canvas *screen_canvas = ScrnGetDrawCanvas();
384 us->flags=flags&INVREND_USERFLAGS;
386 if (r!=NULL)
387 us->draw_rect = *r;
388 else {
389 us->draw_rect.ul.x = 0;
390 us->draw_rect.ul.y = 0;
391 us->draw_rect.lr.x = screen_canvas->bm.w;
392 us->draw_rect.lr.y = screen_canvas->bm.h;
395 gr_init_sub_canvas(screen_canvas, &us->vis_buffer,
396 us->draw_rect.ul.x, us->draw_rect.ul.y,
397 RectWidth(&us->draw_rect), RectHeight(&us->draw_rect));
399 _invGetModelIdx(us);
400 _invInitCamera(us);
402 us->back_buffer=draw_cnv;
404 us->lighting = 1.0;
407 // need to look up inv_rend property here!
408 invRendState *invRendBuildState(int flags, ObjID o_id, const Rect *r, grs_canvas *draw_cnv)
410 invRendState *us=(invRendState *)Malloc(sizeof(invRendState));
411 sInvRenderType defprop = { kInvRenderDefault };
412 sInvRenderType* rendprop = &defprop;
414 PROPERTY_GET(gpInvRendProp,o_id,&rendprop);
415 us->rendtype = *rendprop;
416 us->obj_id = o_id;
418 invrend_init_state(us, flags, r, draw_cnv);
419 return us;
423 // need to look up inv_rend property here!
424 invRendState *invRendBuildStateFromType(int flags, sInvRenderType* type, const Rect *r, grs_canvas *draw_cnv)
426 invRendState *us=(invRendState *)Malloc(sizeof(invRendState));
428 us->obj_id = OBJ_NULL;
429 us->rendtype = *type;
431 invrend_init_state(us, flags, r, draw_cnv);
432 return us;
436 void invRendFreeState(invRendState *us)
438 if (us->flags & INVREND_IN_QUEUE) {
439 us->flags |= INVREND_FREE_ON_RENDER;
440 return;
442 gr_close_canvas(&us->vis_buffer);
443 _invFreeModelIdx(us);
444 Free(us);
448 // set canvas
449 void invRendSetCanvas(invRendState* us, grs_canvas* canv)
451 if (canv)
452 us->back_buffer=canv;
455 // set rect
456 void invRendSetRect(invRendState* us, const Rect *r)
458 if (r!=NULL) {
459 us->draw_rect = *r;
460 gr_close_canvas(&us->vis_buffer);
461 gr_init_sub_canvas(ScrnGetDrawCanvas(), &us->vis_buffer, r->ul.x, r->ul.y, RectWidth(r), RectHeight(r));
465 void invRendSetType(invRendState* us, const sInvRenderType* type)
467 // if same, just exit
468 if (us->rendtype.type == type->type) // slight overuse of "type"
470 if (type->type == kInvRenderDefault
471 || strncmp(us->rendtype.resource.text,
472 type->resource.text,
473 sizeof(us->rendtype.resource.text)) == 0)
474 return;
476 _invFreeModelIdx(us);
477 us->rendtype = *type;
478 _invGetModelIdx(us);
481 // this is the big mess, having to deal with changing whether im now hilight, if my canvas changes, so on
482 void invRendUpdateState(invRendState *us, int flags, ObjID o_id, const Rect *r, grs_canvas *draw_cnv)
484 if ((o_id!=us->obj_id)&&(o_id!=OBJ_NULL))
486 _invFreeModelIdx(us);
487 us->obj_id=o_id;
488 us->rendtype.type = kInvRenderDefault;
489 _invGetModelIdx(us);
490 _invInitCamera(us);
492 invRendSetRect(us,r);
493 invRendSetCanvas(us,draw_cnv);
494 if (flags&INVREND_SET)
496 #ifdef SUPPORT_CACHE
497 if ((flags&INVREND_CACHEPICTURE)!=(us->flags&INVREND_CACHEPICTURE))
498 Warning(("Hey! cant update state and change from double buffered to not in inv_rend\n"));
499 us->flags&=~INVREND_CACHEVALID;
500 #endif
501 us->flags=(us->flags&(~INVREND_USERFLAGS))|(flags&INVREND_USERFLAGS);
505 #define QUEUE_SIZE 25
506 static invRendState *objQueue[QUEUE_SIZE];
507 static int numObjs=0;
509 ///////////////////
510 // draw/update control
511 // Note: we assume draw canvas is locked when this is called.
512 void invRendDrawUpdate(invRendState *us)
514 if (g_lgd3d) {
515 switch (us->flags & (INVREND_HARDWARE|INVREND_TYPE))
517 case INVREND_HARDWARE_QUEUE|INVREND_MODEL:
518 // queue object for hardware accelerated rendering...
519 if (numObjs >= QUEUE_SIZE) {
520 Warning(("invRendDrawUpdate(): too many objects to queue.\n"));
521 } else if (us->back_buffer != NULL) {
522 Warning(("Can't hardware accelerate object rendered off screen.\n"));
523 } else {
524 objQueue[numObjs++] = us;
525 us->flags |= INVREND_IN_QUEUE;
527 break;
528 case INVREND_HARDWARE_IMMEDIATE|INVREND_MODEL:
529 if (us->back_buffer != NULL) {
530 Warning(("Can't hardware accelerate object rendered off screen.\n"));
531 render_single_obj(us, TRUE);
532 } else {
533 extern int rendloop_counter;
534 BOOL bOverlaysWereOn; //zb
536 // @TODO really we want a ScrnBreakLock / ScrnRestoreLock here...
537 ScrnUnlockDrawCanvas();
539 lgd3d_start_frame(rendloop_counter);
540 bOverlaysWereOn = lgd3d_overlays_master_switch( FALSE ); //zb
542 render_single_obj(us, TRUE);
543 lgd3d_set_offsets(0,0);
544 lgd3d_end_frame();
546 if( bOverlaysWereOn ) //zb
547 lgd3d_overlays_master_switch( TRUE ); //zb
549 ScrnLockDrawCanvas();
551 break;
552 default:
553 render_single_obj(us, TRUE);
554 break;
556 } else
557 render_single_obj(us, TRUE);
559 if (us->flags&INVREND_ROTATE)
560 us->off_ang.el[2]+=0x0100;
561 // us->off_ang.el[1]+=0x100; // if you want wack-a-tronic implementation
564 void invRendSetView(invRendState* us, const sInvRendView* view)
566 *(sInvRendView*)us = *view;
569 // Flush objects queued for hardware rendering
570 // @TODO: these are a frame behind similar overlay state
571 void invRendFlushQueue(void)
573 int i;
574 grs_canvas* p_screen_canvas;
576 if (numObjs == 0)
577 return;
579 // Clear the whole z-buffer
580 p_screen_canvas = ScrnGetDrawCanvas();
582 lgd3d_set_offsets(0,0);
583 lgd3d_clear_z_rect(0, 0, p_screen_canvas->bm.w, p_screen_canvas->bm.h);
586 for (i=0; i<numObjs; i++)
588 invRendState *us=objQueue[i];
590 render_single_obj( us, FALSE );
592 us->flags &= ~INVREND_IN_QUEUE;
593 if (us->flags & INVREND_FREE_ON_RENDER)
594 invRendFreeState(us);
596 lgd3d_set_offsets(0,0);
597 numObjs = 0;
600 void invRendGetView(const invRendState* us, sInvRendView * view)
602 *view = *(sInvRendView*)us;
605 ////////////////
606 // build our properties here
609 void invRendInit(void)
611 IResMan *pResMan = AppGetObj(IResMan);
613 gpInvRendProp = CreateInvRenderProp();
614 gpInvRendBitmapPath = IResMan_NewSearchPath(pResMan, BITMAP_PATH);
616 config_get_float("inv_model_zoom",&gRenderZoom);
618 SafeRelease(pResMan);
621 void invRendFreeQueue(void)
623 int i;
625 // Flush queue and free states as appropriate...
626 for (i=0; i<numObjs; i++) {
627 invRendState *us = objQueue[i];
628 us->flags &= ~INVREND_IN_QUEUE;
629 if (us->flags &INVREND_FREE_ON_RENDER)
630 invRendFreeState(us);
632 numObjs = 0;
635 void invRendTerm(void)
637 invRendFreeQueue();
638 SafeRelease(gpInvRendProp);
639 SafeRelease(gpInvRendBitmapPath);