diff options
Diffstat (limited to 'saga/objectmap.cpp')
-rw-r--r-- | saga/objectmap.cpp | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/saga/objectmap.cpp b/saga/objectmap.cpp new file mode 100644 index 0000000000..bd3ec1df8b --- /dev/null +++ b/saga/objectmap.cpp @@ -0,0 +1,556 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ +/* + + Description: + + Object map / Object click-area module + + Notes: + + Polygon Hit Test code ( HitTestPoly() ) adapted from code (C) Eric Haines + appearing in Graphics Gems IV, "Point in Polygon Strategies." + p. 24-46, code: p. 34-45 +*/ + +#include "reinherit.h" + +#include "yslib.h" + +/* + * Uses the following modules: +\*--------------------------------------------------------------------------*/ +#include "cvar_mod.h" +#include "console_mod.h" +#include "gfx_mod.h" +#include "math_mod.h" +#include "font_mod.h" + +/* + * Module options +\*--------------------------------------------------------------------------*/ + +#define R_OBJECTMAP_DEBUG R_DEBUG_INFO + +/* + * Begin module +\*--------------------------------------------------------------------------*/ +#include "objectmap_mod.h" +#include "objectmap.h" + +namespace Saga { + +static R_OBJECTMAP_INFO OMInfo; + +int OBJECTMAP_Register(void) +{ + + CVAR_RegisterFunc(CF_object_info, + "object_info", NULL, R_CVAR_NONE, 0, 0); + + return R_SUCCESS; +} + +int OBJECTMAP_Init(void) +/*--------------------------------------------------------------------------*\ + * Initializes the object map module, creates module allocation context +\*--------------------------------------------------------------------------*/ +{ + R_printf(R_STDOUT, "OBJECTMAP Module: Initializing...\n"); + + OMInfo.initialized = 1; + return R_SUCCESS; +} + +int OBJECTMAP_Shutdown(void) +/*--------------------------------------------------------------------------*\ + * Shuts down the object map module, destroys module allocation context +\*--------------------------------------------------------------------------*/ +{ + if (!OMInfo.initialized) { + return R_FAILURE; + } + + R_printf(R_STDOUT, "OBJECTMAP Module: Shutting down...\n"); + + OBJECTMAP_Free(); + OBJECTMAP_FreeNames(); + + R_printf(R_STDOUT, "OBJECTMAP Module: Shutdown AOK.\n"); + + OMInfo.initialized = 0; + return R_SUCCESS; +} + +int OBJECTMAP_Load(const uchar * om_res, size_t om_res_len) +/*--------------------------------------------------------------------------*\ + * Loads an object map resource ( objects ( clickareas ( points ) ) ) +\*--------------------------------------------------------------------------*/ +{ + const unsigned char *read_p = om_res; + + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + R_POINT *point; + + int i, k, m; + + YS_IGNORE_PARAM(om_res_len); + + if (!OMInfo.initialized) { + R_printf(R_STDERR, + "Error: Object map module not initialized!\n"); + return R_FAILURE; + } + + if (OMInfo.objects_loaded) { + OBJECTMAP_Free(); + } + + /* Obtain object count N and allocate space for N objects + * \*------------------------------------------------------------- */ + OMInfo.n_objects = ys_read_u16_le(read_p, &read_p); + + OMInfo.object_maps = + (R_OBJECTMAP_ENTRY *)malloc(OMInfo.n_objects * sizeof *OMInfo.object_maps); + + if (OMInfo.object_maps == NULL) { + R_printf(R_STDERR, "Error: Memory allocation failed.\n"); + return R_MEM; + } + + /* Load all N objects + * \*------------------------------------------------------------- */ + for (i = 0; i < OMInfo.n_objects; i++) { + + object_map = &OMInfo.object_maps[i]; + object_map->unknown0 = ys_read_u8(read_p, &read_p); + object_map->n_clickareas = ys_read_u8(read_p, &read_p); + object_map->flags = ys_read_u16_le(read_p, &read_p); + object_map->object_num = ys_read_u16_le(read_p, &read_p); + object_map->script_num = ys_read_u16_le(read_p, &read_p); + + object_map->clickareas = + (R_CLICKAREA *)malloc(object_map->n_clickareas * + sizeof *(object_map->clickareas)); + + if (object_map->clickareas == NULL) { + R_printf(R_STDERR, + "Error: Memory allocation failed.\n"); + return R_MEM; + } + + /* Load all clickareas for this object */ + for (k = 0; k < object_map->n_clickareas; k++) { + + clickarea = &object_map->clickareas[k]; + clickarea->n_points = ys_read_u16_le(read_p, &read_p); + assert(clickarea->n_points != 0); + + clickarea->points = + (R_POINT *)malloc(clickarea->n_points * sizeof *(clickarea->points)); + + if (clickarea->points == NULL) { + R_printf(R_STDERR, + "Error: Memory allocation failed.\n"); + return R_MEM; + } + + /* Load all points for this clickarea */ + for (m = 0; m < clickarea->n_points; m++) { + + point = &clickarea->points[m]; + point->x = ys_read_s16_le(read_p, &read_p); + point->y = ys_read_s16_le(read_p, &read_p); + } + +# if R_OBJECTMAP_DEBUG >= R_DEBUG_PARANOID + R_printf(R_STDOUT, + "OBJECTMAP_Load(): " + "Read %d points for clickarea %d in object %d.\n", + clickarea->n_points, k, object_map->object_num); +# endif + } /* End load all clickareas */ + } /* End load all objects */ + + /*-------------------------------------------------------------*/ + OMInfo.objects_loaded = 1; + + return R_SUCCESS; +} + +int OBJECTMAP_Free(void) +/*--------------------------------------------------------------------------*\ + * Frees all storage allocated for the current object map data +\*--------------------------------------------------------------------------*/ +{ + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + + int i, k; + + if (!OMInfo.objects_loaded) { + return R_FAILURE; + } + + for (i = 0; i < OMInfo.n_objects; i++) { + object_map = &OMInfo.object_maps[i]; + + for (k = 0; k < object_map->n_clickareas; k++) { + clickarea = &object_map->clickareas[k]; + free(clickarea->points); + } + free(object_map->clickareas); + } + + if (OMInfo.n_objects) { + free(OMInfo.object_maps); + } + + OMInfo.objects_loaded = 0; + + return R_SUCCESS; +} + +int OBJECTMAP_LoadNames(const unsigned char *onl_res, size_t onl_res_len) +/*--------------------------------------------------------------------------*\ + * Loads an object name list resource +\*--------------------------------------------------------------------------*/ +{ + YS_REG_FUNC(OBJECTMAP_LoadNames); + const unsigned char *read_p = onl_res; + + int table_len; + int n_names; + size_t name_offset; + + int i; + + YS_IGNORE_PARAM(onl_res_len); + + if (OMInfo.names_loaded) { + OBJECTMAP_FreeNames(); + } + + table_len = ys_read_u16_le(read_p, &read_p); + + n_names = table_len / 2 - 2; + OMInfo.n_names = n_names; + +#if 0 +# if R_OBJECTMAP_DEBUG >= R_DEBUG_INFO + R_printf(R_STDOUT, "%s: Loading %d object names.\n", YS_FUNC, n_names); +# endif +#endif + OMInfo.names = (char **)malloc(n_names * sizeof *OMInfo.names); + + if (OMInfo.names == NULL) { + R_printf(R_STDERR, "Error: Memory allocation failed.\n"); + return R_MEM; + } + + for (i = 0; i < n_names; i++) { + name_offset = ys_read_u16_le(read_p, &read_p); + OMInfo.names[i] = (char *)(onl_res + name_offset); + +# if R_OBJECTMAP_DEBUG >= R_DEBUG_VERBOSE + R_printf(R_STDOUT, + "Loaded object name string: %s\n", OMInfo.names[i]); +# endif + } + + OMInfo.names_loaded = 1; + + return R_SUCCESS; +} + +int OBJECTMAP_FreeNames(void) +/*--------------------------------------------------------------------------*\ + * Frees all storage allocated for the current object name list data +\*--------------------------------------------------------------------------*/ +{ + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if (OMInfo.n_names) { + free(OMInfo.names); + } + + OMInfo.names_loaded = 0; + return R_SUCCESS; +} + +int OBJECTMAP_GetName(int object, const char **name) +/*--------------------------------------------------------------------------*\ + * If 'object' is a valid object number in the currently loaded object + * name list resource, the funciton sets '*name' to the descriptive string + * corresponding to 'object' and returns R_SUCCESS. Otherwise it returns + * R_FAILURE. +\*--------------------------------------------------------------------------*/ +{ + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if ((object <= 0) || (object > OMInfo.n_names)) { + return R_FAILURE; + } + + *name = OMInfo.names[object - 1]; + + return R_SUCCESS; +} + +int OBJECTMAP_GetFlags(int object, uint * flags) +{ + int i; + + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if ((object <= 0) || (object > OMInfo.n_names)) { + return R_FAILURE; + } + + for (i = 0; i < OMInfo.n_objects; i++) { + + if (OMInfo.object_maps[i].object_num == object) { + + *flags = OMInfo.object_maps[i].flags; + return R_SUCCESS; + } + } + + return R_FAILURE; +} + +int OBJECTMAP_GetEPNum(int object, int *ep_num) +/*--------------------------------------------------------------------------*\ + * If 'object' is a valid object number in the currently loaded object + * name list resource, the funciton sets '*ep_num' to the entrypoint number + * corresponding to 'object' and returns R_SUCCESS. Otherwise, it returns + * R_FAILURE. +\*--------------------------------------------------------------------------*/ +{ + int i; + + if (!OMInfo.names_loaded) { + return R_FAILURE; + } + + if ((object < 0) || (object > (OMInfo.n_objects + 1))) { + return R_FAILURE; + } + + for (i = 0; i < OMInfo.n_objects; i++) { + + if (OMInfo.object_maps[i].object_num == object) { + + *ep_num = OMInfo.object_maps[i].script_num; + return R_SUCCESS; + } + } + + return R_FAILURE; +} + +int OBJECTMAP_Draw(R_SURFACE * ds, R_POINT * imouse_pt, int color, int color2) +/*--------------------------------------------------------------------------*\ + * Uses GFX_DrawLine to display all clickareas for each object in the + * currently loaded object map resource. +\*--------------------------------------------------------------------------*/ +{ + + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + + char txt_buf[32]; + + int draw_color = color; + int draw_txt = 0; + + int hit_object = 0; + int object_num = 0; + + int pointcount = 0; + int i, k; + + assert(OMInfo.initialized); + + if (!OMInfo.objects_loaded) { + return R_FAILURE; + } + + if (imouse_pt != NULL) { + + if (OBJECTMAP_HitTest(imouse_pt, &object_num) == R_SUCCESS) { + hit_object = 1; + } + } + + for (i = 0; i < OMInfo.n_objects; i++) { + + draw_color = color; + + if (hit_object && + (object_num == OMInfo.object_maps[i].object_num)) { + + snprintf(txt_buf, + sizeof txt_buf, + "obj %d: ? %d, f %X", + OMInfo.object_maps[i].object_num, + OMInfo.object_maps[i].unknown0, + OMInfo.object_maps[i].flags); + + draw_txt = 1; + draw_color = color2; + } + + object_map = &OMInfo.object_maps[i]; + + for (k = 0; k < object_map->n_clickareas; k++) { + + clickarea = &object_map->clickareas[k]; + pointcount = 0; + + if (clickarea->n_points == 2) { + + /* 2 points represent a box */ + GFX_DrawFrame(ds, + &clickarea->points[0], + &clickarea->points[1], draw_color); + } else if (clickarea->n_points > 2) { + + /* Otherwise draw a polyline */ + + GFX_DrawPolyLine(ds, + clickarea->points, + clickarea->n_points, draw_color); + + } + + } /* end for() clickareas */ + } /* end for() objects */ + + if (draw_txt) { + + FONT_Draw(SMALL_FONT_ID, + ds, + txt_buf, + 0, + 2, 2, SYSGFX_GetWhite(), SYSGFX_GetBlack(), FONT_OUTLINE); + } + + return R_SUCCESS; +} + +int OBJECTMAP_HitTest(R_POINT * imouse_pt, int *object_num) +{ + + R_POINT imouse; + R_OBJECTMAP_ENTRY *object_map; + R_CLICKAREA *clickarea; + R_POINT *points; + int n_points; + + int i, k; + + assert((imouse_pt != NULL) && (object_num != NULL)); + + imouse.x = imouse_pt->x; + imouse.y = imouse_pt->y; + + /* Loop through all scene objects */ + for (i = 0; i < OMInfo.n_objects; i++) { + + object_map = &OMInfo.object_maps[i]; + + /* Hit-test all clickareas for this object */ + for (k = 0; k < object_map->n_clickareas; k++) { + + clickarea = &object_map->clickareas[k]; + + n_points = clickarea->n_points; + points = clickarea->points; + + if (n_points == 2) { + /* Hit-test a box region */ + if ((imouse.x > points[0].x) && + (imouse.x <= points[1].x) && + (imouse.y > points[0].y) && + (imouse.y <= points[1].y)) { + + *object_num = object_map->object_num; + + return R_SUCCESS; + } + } else if (n_points > 2) { + /* Hit-test a polygon */ + if (MATH_HitTestPoly(points, n_points, imouse)) { + + *object_num = object_map->object_num; + + return R_SUCCESS; + } + } + + } /* end for() clickareas */ + } /* end for() objects */ + + *object_num = 0; + + return R_FAILURE; +} + +static void CF_object_info(int argc, char *argv[]) +{ + int i; + + YS_IGNORE_PARAM(argc); + YS_IGNORE_PARAM(argv); + + if (!OMInfo.initialized) { + return; + } + + CON_Print("%d objects loaded.", OMInfo.n_objects); + + for (i = 0; i < OMInfo.n_objects; i++) { + + CON_Print("%s:", OMInfo.names[i]); + CON_Print + ("%d. Unk1: %d, flags: %X, name_i: %d, scr_n: %d, ca_ct: %d", + i, OMInfo.object_maps[i].unknown0, + OMInfo.object_maps[i].flags, + OMInfo.object_maps[i].object_num, + OMInfo.object_maps[i].script_num, + OMInfo.object_maps[i].n_clickareas); + + } + + return; +} + +} // End of namespace Saga |