/** * \brief Clamps the vertices of the stick so that they fit above the previous stick's vertices. * \param self Terrain stick. * \param prev Terrain stick. */ void liext_terrain_stick_clamp_vertices_bottom ( LIExtTerrainStick* self, LIExtTerrainStick* prev) { int x; int z; for (z = 0 ; z < 2 ; z++) { for (x = 0 ; x < 2 ; x++) { if (prev != NULL) { self->vertices[x][z].offset = LIMAT_MAX ( self->vertices[x][z].offset, prev->vertices[x][z].offset - self->height); } else { self->vertices[x][z].offset = LIMAT_MAX ( self->vertices[x][z].offset, -self->height); } } } }
/** * \brief Sets the vertex offsets of the stick. * * The values chosen are the maximum of the current ones and those given in * the slope argument. * * \param self Stick. * \param slope List of four floats. * \param offset Extra offset to add to the slope values. */ void liext_terrain_stick_set_vertices_max ( LIExtTerrainStick* self, const float* slope, float offset) { if (self == NULL) return; self->vertices[0][0].offset = LIMAT_MAX (self->vertices[0][0].offset, slope[0] + offset); self->vertices[1][0].offset = LIMAT_MAX (self->vertices[1][0].offset, slope[1] + offset); self->vertices[0][1].offset = LIMAT_MAX (self->vertices[0][1].offset, slope[2] + offset); self->vertices[1][1].offset = LIMAT_MAX (self->vertices[1][1].offset, slope[3] + offset); }
/** * \brief Gets the full size request of the widget. * * Returns the larger of the user and hard size requests, combined with the * style paddings of the widget. * * \param self Widget. * \param request Return location for the size. */ void liwdg_widget_get_request ( LIWdgWidget* self, LIWdgSize* request) { request->width = self->request[0].width; request->height = self->request[0].height; if (self->request[1].width != -1) request->width = LIMAT_MAX (request->width, self->request[1].width); if (self->request[1].height != -1) request->height = LIMAT_MAX (request->height, self->request[1].height); if (self->request[2].width != -1) request->width = LIMAT_MAX (request->width, self->request[2].width); if (self->request[2].height != -1) request->height = LIMAT_MAX (request->height, self->request[2].height); }
static void Terrain_add_box (LIScrArgs* args) { int grid_x1; int grid_z1; int grid_x2; int grid_z2; float world_y; float world_h; int material; /* Get the arguments. */ if (!liscr_args_geti_int (args, 0, &grid_x1) || grid_x1 < 0) return; if (!liscr_args_geti_int (args, 1, &grid_z1) || grid_z1 < 0) return; if (!liscr_args_geti_int (args, 2, &grid_x2) || grid_x2 < grid_x1) return; if (!liscr_args_geti_int (args, 3, &grid_z2) || grid_z2 < grid_z1) return; if (!liscr_args_geti_float (args, 4, &world_y) || world_y < 0.0f) return; if (!liscr_args_geti_float (args, 5, &world_h)) return; world_h = LIMAT_MAX (world_h, LIEXT_STICK_EPSILON); if (!liscr_args_geti_int (args, 6, &material) || material < 0) return; liscr_args_seti_int (args, liext_terrain_add_box (args->self, grid_x1, grid_z1, grid_x2, grid_z2, world_y, world_h, material, NULL, NULL)); }
static void Terrain_add_stick_filter_mask (LIScrArgs* args) { int grid_x; int grid_z; float world_y; float world_h; int material; int mask; /* Get the arguments. */ if (!liscr_args_geti_int (args, 0, &grid_x) || grid_x < 0) return; if (!liscr_args_geti_int (args, 1, &grid_z) || grid_z < 0) return; if (!liscr_args_geti_float (args, 2, &world_y) || world_y < 0.0f) return; if (!liscr_args_geti_float (args, 3, &world_h)) return; world_h = LIMAT_MAX (world_h, LIEXT_STICK_EPSILON); if (!liscr_args_geti_int (args, 4, &material) || material < 0) return; if (!liscr_args_geti_int (args, 5, &mask) || mask < 0) return; liscr_args_seti_bool (args, liext_terrain_add_stick (args->self, grid_x, grid_z, world_y, world_h, material, liext_terrain_stick_filter_mask, &mask)); }
static void Sound_set_music_fading (LIScrArgs* args) { #ifndef LI_DISABLE_SOUND float value; LIExtModule* module; if (liscr_args_geti_float (args, 0, &value)) { value = LIMAT_MAX (0.0f, value); module = liscr_script_get_userdata (args->script, LIEXT_SCRIPT_SOUND); liext_sound_set_music_fading (module, value); } #endif }
static void Model_calculate_lod (LIScrArgs* args) { int levels = 5; float factor = 0.3f; LIEngModel* model; LIMdlBuilder* builder; model = args->self; if (liscr_args_geti_int (args, 0, &levels)) levels = LIMAT_MAX (1, levels); if (liscr_args_geti_float (args, 1, &factor)) factor = LIMAT_CLAMP (factor, 0.0f, 1.0f); builder = limdl_builder_new (model->model); if (builder == NULL) return; limdl_builder_calculate_lod (builder, levels, factor); limdl_builder_finish (builder); limdl_builder_free (builder); liscr_args_seti_bool (args, 1); }
static LIMdlEdge* private_extract_edges ( LIMdlBuilder* self, LIMdlBuilderLod* lod, int index_count, int* edge_count) { int i; int j; int k; uint32_t i1; uint32_t i2; uint32_t index; uint32_t face[4]; LIAlgU32dic* dict; LIMdlEdge* edge; LIMdlEdge* edges; LIMdlBuilderFaces* group; /* Allocate the edge list. */ edges = lisys_calloc (index_count, sizeof (LIMdlEdge)); if (edges == NULL) return NULL; *edge_count = 0; /* Allocate a temporary lookup table. */ dict = lialg_u32dic_new (); if (dict == NULL) { lisys_free (edges); return NULL; } /* Extract the edges using the index lists. */ for (i = 0 ; i < lod->face_groups.count ; i++) { group = lod->face_groups.array + i; for (j = 0 ; j < group->indices.count ; j += 3) { face[0] = group->indices.array[j]; face[1] = group->indices.array[j + 1]; face[2] = group->indices.array[j + 2]; face[3] = face[0]; for (k = 0 ; k < 3 ; k++) { i1 = LIMAT_MIN (face[k], face[k + 1]); i2 = LIMAT_MAX (face[k], face[k + 1]); index = i1 + i2 * index_count; edge = lialg_u32dic_find (dict, index); if (edge == NULL) { edge = edges + *edge_count; edge->i1 = i1; edge->i2 = i2; edge->users = 1; lialg_u32dic_insert (dict, index, edge); *edge_count += 1; } else edge->users++; } } } /* Free the lookup table. */ lialg_u32dic_free (dict); return edges; }
static void Terrain_count_column_materials (LIScrArgs* args) { int grid_x; int grid_z; float y; float min; float max; float length; float start = 0.0f; float height = -1.0f; LIExtTerrainColumn* column; LIExtTerrainStick* stick; /* Get the arguments. */ if (!liscr_args_geti_int (args, 0, &grid_x) || grid_x < 0) return; if (!liscr_args_geti_int (args, 1, &grid_z) || grid_z < 0) return; if (liscr_args_geti_float (args, 2, &start)) start = LIMAT_MAX (0.0f, start); if (liscr_args_geti_float (args, 3, &height)) height = LIMAT_MAX (0.0f, height); if (!liscr_args_geti_table (args, 4)) return; /* Get the column. */ column = liext_terrain_get_column (args->self, grid_x, grid_z); if (column == NULL) return; /* Count the materials and add the counts to the table. */ for (y = 0.0f, stick = column->sticks ; stick != NULL ; y += stick->height, stick = stick->next) { if (height >= 0.0f) { min = LIMAT_MAX (y, start); max = LIMAT_MIN (y + stick->height, start + height); } else { min = LIMAT_MAX (y, start); max = y + stick->height; } length = max - min; if (length > 0.0f) { lua_pushnumber (args->lua, stick->material); lua_pushnumber (args->lua, stick->material); lua_gettable (args->lua, -3); if (lua_type (args->lua, -1) == LUA_TNUMBER) length += lua_tonumber (args->lua, -1); lua_pop (args->lua, 1); lua_pushnumber (args->lua, length); lua_settable (args->lua, -3); } } /* Add the remainder if the range was given. */ if (height >= 0.0f) { length = start + height - y; if (length > 0.0f) { lua_pushnumber (args->lua, 0); lua_pushnumber (args->lua, 0); lua_gettable (args->lua, -3); if (lua_type (args->lua, -1) == LUA_TNUMBER) length += lua_tonumber (args->lua, -1); lua_pop (args->lua, 1); lua_pushnumber (args->lua, length); lua_settable (args->lua, -3); } } }
static void Voxel_find_blocks (LIScrArgs* args) { int sx; int sy; int sz; int index; int line; int stamp; float radius; LIAlgRange sectors; LIAlgRange blocks; LIAlgRange range; LIAlgRangeIter iter0; LIAlgRangeIter iter1; LIExtModule* module; LIMatVector min; LIMatVector max; LIMatVector point; LIMatVector size; LIVoxBlock* block; LIVoxSector* sector; /* Initialize arguments. */ if (!liscr_args_gets_vector (args, "point", &point)) return; liscr_args_gets_float (args, "radius", &radius); liscr_args_set_output (args, LISCR_ARGS_OUTPUT_TABLE_FORCE); module = liscr_script_get_userdata (args->script, LIEXT_SCRIPT_VOXEL); line = module->voxels->blocks_per_line * module->voxels->sectors->count; /* Calculate sight volume. */ size = limat_vector_init (radius, radius, radius); min = limat_vector_subtract (point, size); max = limat_vector_add (point, size); sectors = lialg_range_new_from_aabb (&min, &max, module->voxels->sectors->width); sectors = lialg_range_clamp (sectors, 0, module->voxels->sectors->count - 1); blocks = lialg_range_new_from_aabb (&min, &max, module->voxels->sectors->width / module->voxels->blocks_per_line); blocks = lialg_range_clamp (blocks, 0, module->voxels->blocks_per_line * module->voxels->sectors->count - 1); /* Loop through visible sectors. */ LIALG_RANGE_FOREACH (iter0, sectors) { /* Get voxel sector. */ sector = lialg_sectors_data_index (module->voxels->sectors, LIALG_SECTORS_CONTENT_VOXEL, iter0.index, 0); if (sector == NULL) continue; /* Calculate visible block range. */ livox_sector_get_offset (sector, &sx, &sy, &sz); sx *= module->voxels->blocks_per_line; sy *= module->voxels->blocks_per_line; sz *= module->voxels->blocks_per_line; range.min = 0; range.max = module->voxels->blocks_per_line; range.minx = LIMAT_MAX (blocks.minx - sx, 0); range.miny = LIMAT_MAX (blocks.miny - sy, 0); range.minz = LIMAT_MAX (blocks.minz - sz, 0); range.maxx = LIMAT_MIN (blocks.maxx - sx, module->voxels->blocks_per_line - 1); range.maxy = LIMAT_MIN (blocks.maxy - sy, module->voxels->blocks_per_line - 1); range.maxz = LIMAT_MIN (blocks.maxz - sz, module->voxels->blocks_per_line - 1); /* Loop through visible blocks. */ LIALG_RANGE_FOREACH (iter1, range) { block = livox_sector_get_block (sector, iter1.x, iter1.y, iter1.z); stamp = livox_block_get_stamp (block); index = (sx + iter1.x) + (sy + iter1.y) * line + (sz + iter1.z) * line * line; liscr_args_setf_float (args, index, stamp); }
static void private_rebuild ( LIWdgWidget* self, int flags) { int x; int y; int wmax; int hmax; int wpad; int hpad; int wreq; int hreq; int start; int expand; LIWdgWidget* child; LIWdgRect rect; LIWdgSize size; if (self->rebuilding) return; self->rebuilding = 1; if (self->homogeneous) { if (1) { /* Calculate the width request. */ wmax = 0; wpad = self->margin_right + self->margin_left; for (x = 0 ; x < self->width ; x++) { if (self->cols[x].request > 0) { if (x != self->width - 1) wpad += self->col_spacing; if (wmax < self->cols[x].request) wmax = self->cols[x].request; } } wreq = wpad + wmax * self->width; /* Calculate the height request. */ hmax = 0; hpad = self->margin_top + self->margin_bottom; for (y = 0 ; y < self->height ; y++) { if (self->rows[y].request > 0) { if (y != self->height - 1) hpad += self->row_spacing; if (hmax < self->rows[y].request) hmax = self->rows[y].request; } } hreq = hpad + hmax * self->height; /* Set the size request. */ liwdg_widget_set_request (self, 0, wreq, hreq); liwdg_widget_get_allocation (self, &rect); liwdg_widget_get_request (self, &size); rect.width = LIMAT_MAX (size.width, rect.width); rect.height = LIMAT_MAX (size.height, rect.height); liwdg_widget_set_allocation (self, rect.x, rect.y, rect.width, rect.height); } liwdg_widget_get_allocation (self, &rect); if (flags & PRIVATE_REBUILD_HORZ) { /* Get horizontal expansion. */ if (self->col_expand > 0) { expand = rect.width - wreq; lisys_assert (expand >= 0); expand /= self->width; } else expand = 0; /* Set horizontal allocations. */ start = self->margin_left; for (x = 0 ; x < self->width ; x++) { self->cols[x].start = start; self->cols[x].allocation = wmax; self->cols[x].allocation += expand; start += self->cols[x].allocation; start += self->col_spacing; } } if (flags & PRIVATE_REBUILD_VERT) { /* Get vertical expansion. */ if (self->row_expand > 0) { expand = rect.height - hreq; lisys_assert (expand >= 0); expand /= self->height; } else expand = 0; /* Set vertical allocations. */ start = self->margin_top; for (y = 0 ; y < self->height ; y++) { self->rows[y].start = start; self->rows[y].allocation = hmax; self->rows[y].allocation += expand; start += self->rows[y].allocation; start += self->row_spacing; } } } else { if (flags & PRIVATE_REBUILD_REQUEST) { /* Calculate the width request. */ wreq = self->margin_right + self->margin_left; for (x = 0 ; x < self->width ; x++) { if (self->cols[x].request > 0) { if (x != self->width - 1) wreq += self->col_spacing; wreq += self->cols[x].request; } } /* Calculate the height request. */ hreq = self->margin_top + self->margin_bottom; for (y = 0 ; y < self->height ; y++) { if (self->rows[y].request > 0) { if (y != self->height - 1) hreq += self->row_spacing; hreq += self->rows[y].request; } } /* Set the size request. */ liwdg_widget_set_request (self, 0, wreq, hreq); liwdg_widget_get_allocation (self, &rect); liwdg_widget_get_request (self, &size); rect.width = LIMAT_MAX (size.width, rect.width); rect.height = LIMAT_MAX (size.height, rect.height); liwdg_widget_set_allocation (self, rect.x, rect.y, rect.width, rect.height); } liwdg_widget_get_allocation (self, &rect); if (flags & PRIVATE_REBUILD_HORZ) { /* Get horizontal expansion. */ if (self->col_expand > 0) { expand = rect.width - self->margin_left - self->margin_right; lisys_assert (expand >= 0); for (x = 0 ; x < self->width ; x++) { if (self->cols[x].request) { expand -= self->cols[x].request; if (x < self->width - 1) expand -= self->col_spacing; } } lisys_assert (expand >= 0); expand /= self->col_expand; } else expand = 0; /* Set horizontal allocations. */ start = self->margin_left; for (x = 0 ; x < self->width ; x++) { self->cols[x].start = start; self->cols[x].allocation = self->cols[x].request; if (self->cols[x].expand) self->cols[x].allocation += expand; start += self->cols[x].allocation; if (self->cols[x].request) start += self->col_spacing; } } if (flags & PRIVATE_REBUILD_VERT) { /* Get vertical expansion. */ if (self->row_expand > 0) { expand = rect.height - self->margin_top - self->margin_bottom; lisys_assert (expand >= 0); for (y = 0 ; y < self->height ; y++) { if (self->rows[y].request) { expand -= self->rows[y].request; if (y < self->height - 1) expand -= self->row_spacing; } } lisys_assert (expand >= 0); expand /= self->row_expand; } else expand = 0; /* Set vertical allocations. */ start = self->margin_top; for (y = 0 ; y < self->height ; y++) { self->rows[y].start = start; self->rows[y].allocation = self->rows[y].request; if (self->rows[y].expand) self->rows[y].allocation += expand; start += self->rows[y].allocation; if (self->rows[y].request) start += self->row_spacing; } } } if (flags & PRIVATE_REBUILD_CHILDREN) { liwdg_widget_get_allocation (self, &rect); /* Set positions of widgets. */ for (x = 0 ; x < self->width ; x++) { for (y = 0 ; y < self->height ; y++) { child = self->cells[x + y * self->width].child; if (child != NULL) { liwdg_widget_set_allocation (child, rect.x + self->cols[x].start, rect.y + self->rows[y].start, self->cols[x].allocation, self->rows[y].allocation); } } } for (child = self->children ; child != NULL ; child = child->below) liwdg_widget_child_request (self, child); } self->rebuilding = 0; }
/** * \brief Subtracts a stick from this one. * \param self Terrain stick. * \param y Vertical offset of the subtracted stick, relative to the stick bottom. * \param h Height of the subtracted stick. * \param bot00 Bottom surface vertex offsets, relative to the bottom of the subtracted stick. * \param bot10 Bottom surface vertex offsets, relative to the bottom of the subtracted stick. * \param bot01 Bottom surface vertex offsets, relative to the bottom of the subtracted stick. * \param bot11 Bottom surface vertex offsets, relative to the bottom of the subtracted stick. * \param top00 Top surface vertex offsets, relative to the top of the subtracted stick. * \param top10 Top surface vertex offsets, relative to the top of the subtracted stick. * \param top01 Top surface vertex offsets, relative to the top of the subtracted stick. * \param top11 Top surface vertex offsets, relative to the top of the subtracted stick. * \return Number between 1-6, or 0 if ran out of memory. */ int liext_terrain_stick_subtract ( LIExtTerrainStick* self, float y, float h, float bot00, float bot10, float bot01, float bot11, float top00, float top10, float top01, float top11) { LIExtTerrainStick* stick; /* A) Is the stick completely below us? * * .....SSSSSSSSSS..... * XXX??............... */ if (y + h <= 0.0f) { /* In this case, nothing is done. The vertices of the stick may still overlap with us, but that should be handled by calling this function for the previous stick. */ return 1; } /* B) Is the stick completely above us? * * .....SSSSSSSSSS..... * ...............??XXX */ if (y >= self->height) { /* In this case, only the vertices of the stick may change, but the height and position remain the same. The vertices are clipped so that they stay below the bottom of the subtracted stick, in the manner similar to case E. */ self->vertices[0][0].offset = LIMAT_MIN (self->vertices[0][0].offset, y + bot00 - self->height); self->vertices[1][0].offset = LIMAT_MIN (self->vertices[1][0].offset, y + bot10 - self->height); self->vertices[0][1].offset = LIMAT_MIN (self->vertices[0][1].offset, y + bot01 - self->height); self->vertices[1][1].offset = LIMAT_MIN (self->vertices[1][1].offset, y + bot11 - self->height); return 2; } /* C) Does the stick replace us completely? * * .....SSSSSSSSSS..... * ..???XXXXXXXXXX???.. */ if (y <= 0.0f && y + h >= self->height) { /* In this case, the stick would become degenerate since its height becomes zero. We just indicate that with the return value. The caller should decide what to do about degenerate sticks. */ return 3; } /* D) Does the stick replace part of the bottom? * * .....SSSSSSSSSS..... * ..???XXXXX.......... */ if (y <= 0.0f) { /* In this case, the stick is shortened by the length of the intersection. As we assume that this function has been called for the previous stick, we also adjust the top surface so that the vertices are above the vertices of the previous stick. */ /* Note the the Y offset of this stick is considered to increase the same amount as its height decreases, meaning that the vertices technically remain at the same absolute positions. This means that the original original absolute Y coordinates must be used when fixing the offsets of the surface vertices. */ self->vertices[0][0].offset = LIMAT_MAX (self->vertices[0][0].offset, y + h + top00 - self->height); self->vertices[1][0].offset = LIMAT_MAX (self->vertices[1][0].offset, y + h + top10 - self->height); self->vertices[0][1].offset = LIMAT_MAX (self->vertices[0][1].offset, y + h + top01 - self->height); self->vertices[1][1].offset = LIMAT_MAX (self->vertices[1][1].offset, y + h + top11 - self->height); self->height -= y + h; private_clamp_vertices (self, self->next); return 4; } /* E) Does the stick replace part of the top? * * .....SSSSSSSSSS..... * ..........XXXXX???.. */ if (y + h >= self->height) { /* In this case, the stick is shortened by the length of the intersection. The vertices are first raised by the length of the intersection so that they will be at the original absolute Y offsets. Then, they are clamped to be below the bottom vertices of the subtracted stick, similar to case B. */ self->vertices[0][0].offset += self->height - y; self->vertices[1][0].offset += self->height - y; self->vertices[0][1].offset += self->height - y; self->vertices[1][1].offset += self->height - y; self->height = y; self->vertices[0][0].offset = LIMAT_MIN (self->vertices[0][0].offset, y + bot00 - self->height); self->vertices[1][0].offset = LIMAT_MIN (self->vertices[1][0].offset, y + bot10 - self->height); self->vertices[0][1].offset = LIMAT_MIN (self->vertices[0][1].offset, y + bot01 - self->height); self->vertices[1][1].offset = LIMAT_MIN (self->vertices[1][1].offset, y + bot11 - self->height); return 5; } /* F) Does the stick replace part of the middle? * * .....SSSSSSSSSS..... * ........XXXX........ */ if (y > 0.0f && y + h < self->height) { /* In this case, the stick is split in two parts so that the split point lies at the start of the subtracted stick. The second part of the stick is allocated and inserted after this stick. After that, the vertices of this stick are modified similar to case E. The vertices of the next stick are clamped so that they will be above the top vertices of the subtracted stick. */ stick = liext_terrain_stick_new (self->material, self->height - y - h); if (stick == NULL) return 0; stick->vertices[0][0].offset = LIMAT_MAX (self->vertices[0][0].offset, y + h + top00 - self->height); stick->vertices[1][0].offset = LIMAT_MAX (self->vertices[1][0].offset, y + h + top10 - self->height); stick->vertices[0][1].offset = LIMAT_MAX (self->vertices[0][1].offset, y + h + top01 - self->height); stick->vertices[1][1].offset = LIMAT_MAX (self->vertices[1][1].offset, y + h + top11 - self->height); private_clamp_vertices (stick, self->next); stick->next = self->next; self->next = stick; self->vertices[0][0].offset += self->height - y; self->vertices[1][0].offset += self->height - y; self->vertices[0][1].offset += self->height - y; self->vertices[1][1].offset += self->height - y; self->height = y; self->vertices[0][0].offset = LIMAT_MIN (self->vertices[0][0].offset, y + bot00 - self->height); self->vertices[1][0].offset = LIMAT_MIN (self->vertices[1][0].offset, y + bot10 - self->height); self->vertices[0][1].offset = LIMAT_MIN (self->vertices[0][1].offset, y + bot01 - self->height); self->vertices[1][1].offset = LIMAT_MIN (self->vertices[1][1].offset, y + bot11 - self->height); return 6; } /* Only the above six cases are possible. */ lisys_assert (0); return 0; }