/******************************************************************************* * apps/graphics/traveler/tools/tcledit/tcl_paint.c * * Copyright (C) 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /******************************************************************************* * Included files ****************************************************************************/ #include #include #include #include #include #ifndef NO_XSHM # include # include #endif #include "trv_types.h" #include "debug.h" #include "wld_mem.h" #include "wld_bitmaps.h" #include "wld_plane.h" #include "wld_utils.h" #include "tcl_x11graphics.h" /******************************************************************************* * Pre-processor Definitions ****************************************************************************/ #define LINE_THICKNESS_DELTA 1 /******************************************************************************* * Private Functions ****************************************************************************/ /******************************************************************************* * Function: tcl_color_index * Description: ***************************************************************************/ static int tcl_color_index(tcl_window_t *w) { int ndx; if (g_edit_mode != EDITMODE_NEW) { ndx = POS_COLORS * NUM_COLORS; } else if (g_edit_plane == w->plane) { ndx = SEL_COLORS * NUM_COLORS; } else { ndx = NSEL_COLORS * NUM_COLORS; } return ndx; } /**************************************************************************** * Function: tcl_paint_rectangle * Description: ***************************************************************************/ static void tcl_paint_rectangle(tcl_window_t *w, int hleft, int hright, int vtop, int vbottom, dev_pixel_t pixel) { dev_pixel_t *rowstart; dev_pixel_t *dest; int row; int col; /* Paint from top to bottom */ rowstart = w->frameBuffer + vtop * w->width; for (row = vtop; row <= vbottom; row++) { /* Paint from left to right */ dest = rowstart + hleft; for (col = hleft; col <= hright; col++) { *dest++ = pixel; } rowstart += w->width; } } /**************************************************************************** * Function: tcl_paint_coplanar_rectangle * Description: ***************************************************************************/ static void tcl_paint_coplanar_rectangle(tcl_window_t *w, rect_data_t *ptr, int hoffset, int voffset, dev_pixel_t pixel) { int hleft; int hright; int vtop; int vbottom; /* Get the left side offset and verify that some part of the rectangle lies * to the left of the right side of the display. */ hleft = ptr->hstart - hoffset; if (hleft >= g_view_size) { return; } if (hleft < 0) { hleft = 0; } /* Get the right side offset and verify that some part of the rectangle lies * to the right of the left side of the display. */ hright = ptr->hend - hoffset; if (hright < 0) { return; } if (hright >= g_view_size) { hright = g_view_size - 1; } /* Get the top side offset and verify that some part of the rectangle lies * above the bottom of the display. */ vtop = ptr->vstart - voffset; if (vtop >= g_view_size) { return; } if (vtop < 0) { vtop = 0; } /* Get the bottom side offset and verify that some part of the rectangle lies * below the top of the display. */ vbottom = ptr->vend - voffset; if (vbottom < 0) { return; } if (vbottom >= g_view_size) { vbottom = g_view_size - 1; } /* If we are viewing the Z plane, then the vpos is "down" the screen from the * top. Otherwise, it is "up" the screen from the bottom. */ if (w->plane != EDITPLANE_Z) { int vtmp = vbottom; vbottom = g_view_size - vtop - 1; vtop = g_view_size - vtmp - 1; } /* We now have some rectangle that we know is to fully on the the display. * Get the display positions of the rectangle */ hleft = (hleft) * w->width / g_view_size; hright = (hright) * w->width / g_view_size; vtop = (vtop) * w->height / g_view_size; vbottom = (vbottom) * w->height / g_view_size; /* Paint it */ tcl_paint_rectangle(w, hleft, hright, vtop, vbottom, pixel); } /**************************************************************************** * Function: tcl_paint_horizontal_rectangle * Description: ***************************************************************************/ static int tcl_check_horizontal_rectangle(tcl_window_t *w, rect_data_t *ptr, int pos) { int posstart; int posend; /* Search the plane list for every place whose "level" component includes the * current map level. This will be the vertical component of the rectangle * in every case except for EDITPLANE_X: * * w->plane vhead level component EDITPLANE_X g_zplane_list H (= X) EDITPLANE_Y * g_zplane_list V (= Y) EDITPLANE_Z g_yplane_list V (= Z) */ if (w->plane != EDITPLANE_X) { posstart = ptr->vstart; posend = ptr->vend; } else { posstart = ptr->hstart; posend = ptr->hend; } /* Verify the the vertical rectangle intersects the viewing plane */ return ((posstart <= pos) && (posend >= pos)); } /**************************************************************************** * Function: tcl_paint_horizontal_rectangle * Description: ***************************************************************************/ static void tcl_paint_horizontal_rectangle(tcl_window_t *w, rect_data_t *ptr, int hoffset, int voffset, dev_pixel_t pixel) { int hleft; int hright; int vtop; int vbottom; /* Get the "vertical" position of the horizontal line. This will always be * the plane component of the rectangle, but will have to be "flipped" if the * viewing plane is not EDITPLANE_Z: * * w->plane vhead vertical component EDITPLANE_X g_zplane_list plane (= Z) * EDITPLANE_Y g_zplane_list plane (= Z) EDITPLANE_Z g_yplane_list plane (= Y) */ vtop = ptr->plane - voffset; if ((vtop < 0) || (vtop >= g_view_size)) { return; } if (w->plane != EDITPLANE_Z) { vtop = g_view_size - vtop - 1; } /* Get the extent of the horizontal line. This will be the horizontal * component of the rectangle in every case except when the viewing plane if * EDITPLANE_X * * w->plane vhead horizontal component EDITPLANE_X g_zplane_list V (= Y) EDITPLANE_X * g_zplane_list H (= X) EDITPLANE_X g_yplane_list H (= X) */ if (w->plane != EDITPLANE_X) { hleft = ptr->hstart; hright = ptr->hend; } else { hleft = ptr->vstart; hright = ptr->vend; } /* Get the left side offset and verify that some part of the rectangle lies * to the left of the right side of the display. */ hleft -= hoffset; if (hleft >= g_view_size) { return; } if (hleft < 0) { hleft = 0; } /* Get the right side offset and verify that some part of the rectangle lies * to the right of the left side of the display. */ hright -= hoffset; if (hright < 0) { return; } if (hright >= g_view_size) { hright = g_view_size - 1; } /* We now have some line segment that we know is to fully on the the display. * Get the display positions of the line segment. */ hleft = hleft * w->width / g_view_size; hright = hright * w->width / g_view_size; vtop = vtop * w->height / g_view_size; /* Apply Line thickness to get a narrow rectangle */ vbottom = vtop + LINE_THICKNESS_DELTA; if (vbottom >= w->height) { vbottom = w->height - 1; } vtop -= LINE_THICKNESS_DELTA; if (vtop < 0) { vtop = 0; } /* Paint it */ tcl_paint_rectangle(w, hleft, hright, vtop, vbottom, pixel); } /**************************************************************************** * Function: tcl_check_vertical_rectangle * Description: ***************************************************************************/ static int tcl_check_vertical_rectangle(tcl_window_t *w, rect_data_t *ptr, int pos) { int posstart; int posend; /* Search the plane list for every place whose "level" component includes the * current map level. This will be the horizontal component of the rectangle * in every case except for EDITPLANE_Z * * x->plane hhead level component EDITPLANE_X g_yplane_list H (= X) EDITPLANE_Y * g_xplane_list H (= Y) EDITPLANE_Z g_xplane_list V (= Z) */ if (w->plane != EDITPLANE_Z) { posstart = ptr->hstart; posend = ptr->hend; } else { posstart = ptr->vstart; posend = ptr->vend; } /* Verify the the vertical rectangle intersects the viewing plane */ return ((posstart <= pos) && (posend >= pos)); } /**************************************************************************** * Function: tcl_paint_vertical_rectangle * Description: ***************************************************************************/ static void tcl_paint_vertical_rectangle(tcl_window_t *w, rect_data_t *ptr, int hoffset, int voffset, dev_pixel_t pixel) { int hleft; int hright; int vtop; int vbottom; /* Get the "horizontal" position of the vertical line. This will always be * the plane component of the rectangle: * * w->plane hhead horizontal component EDITPLANE_X g_yplane_list plane (= Y) * EDITPLANE_Y g_xplane_list plane (= X) EDITPLANE_Z g_xplane_list plane (= X) */ hleft = ptr->plane - hoffset; if ((hleft < 0) || (hleft >= g_view_size)) { return; } /* Get the extent of the vertical line. This will be the vertical component * of the rectangle in every case except when the viewing plane is * EDITPLANE_Z and will have to be "flipped" if the viewing plane is not * EDITPLANE_Z: * * w->plane hhead horizontal component EDITPLANE_X g_yplane_list V (= Z) EDITPLANE_Y * g_xplane_list V (= Z) EDITPLANE_Z g_xplane_list H (= Y) */ if (w->plane != EDITPLANE_Z) { vtop = ptr->vstart; vbottom = ptr->vend; } else { vtop = ptr->hstart; vbottom = ptr->hend; } /* Get the top side offset and verify that some part of the rectangle lies * above the bottom of the display. */ vtop -= voffset; if (vtop >= g_view_size) { return; } if (vtop < 0) { vtop = 0; } /* Get the bottom side offset and verify that some part of the rectangle lies * below the top of the display */ vbottom -= voffset; if (vbottom < 0) { return; } if (vbottom >= g_view_size) { vbottom = g_view_size - 1; } /* Flip if necessary */ if (w->plane != EDITPLANE_Z) { int vtmp = vbottom; vbottom = g_view_size - vtop - 1; vtop = g_view_size - vtmp - 1; } /* We now have some line segment that we know is to fully on the the display. * Get the display positions of the line segment */ hleft = hleft * w->width / g_view_size; vtop = vtop * w->height / g_view_size; vbottom = vbottom * w->height / g_view_size; /* Apply Line thickness to get a narrow rectangle */ hright = hleft + LINE_THICKNESS_DELTA; if (hright >= w->width) { hright = w->width; } hleft -= LINE_THICKNESS_DELTA; if (hleft < 0) { hleft = 0; } /* Paint it */ tcl_paint_rectangle(w, hleft, hright, vtop, vbottom, pixel); } /******************************************************************************* * Public Functions ****************************************************************************/ /**************************************************************************** * Function: tcl_paint_background * Description: ***************************************************************************/ void tcl_paint_background(tcl_window_t *w) { dev_pixel_t *dest; dev_pixel_t pixel; int ndx = tcl_color_index(w); int i; ginfo("g_edit_mode=%d g_edit_plane=%d plane=%d ndx=%d\n", g_edit_mode, g_edit_plane, w->plane, ndx); pixel = w->colorLookup[ndx + BKGD_COLOR]; dest = w->frameBuffer; ginfo("ndx=%d dest=%p pixel=0x%06lx\n", ndx, dest, pixel); for (i = 0; i < w->width * w->height; i++) { *dest++ = pixel; } } /**************************************************************************** * Function: tcl_paint_position * Description: ***************************************************************************/ void tcl_paint_position(tcl_window_t *w) { /* Only show the position cursor in POS mode */ if (g_edit_mode == EDITMODE_POS) { dev_pixel_t *dest; dev_pixel_t pixel; int ndx = tcl_color_index(w); int hpos; int vpos; int i; ginfo("plane=%d ndx=%d\n", w->plane, ndx); /* Horizontal and vertical positions will depend on which plane is * selected. */ switch (w->plane) { default: case EDITPLANE_X: hpos = g_plane_position[EDITPLANE_Y] - g_coord_offset[EDITPLANE_Y]; vpos = g_plane_position[EDITPLANE_Z] - g_coord_offset[EDITPLANE_Z]; vpos = g_view_size - vpos - 1; break; case EDITPLANE_Y: hpos = g_plane_position[EDITPLANE_X] - g_coord_offset[EDITPLANE_X]; vpos = g_plane_position[EDITPLANE_Z] - g_coord_offset[EDITPLANE_Z]; vpos = g_view_size - vpos - 1; break; case EDITPLANE_Z: hpos = g_plane_position[EDITPLANE_X] - g_coord_offset[EDITPLANE_X]; vpos = g_plane_position[EDITPLANE_Y] - g_coord_offset[EDITPLANE_Y]; break; } /* Scale the position to fit in the display */ hpos = (hpos * w->width) / g_view_size; vpos = (vpos * w->height) / g_view_size; /* Paint the horizontal line */ pixel = w->colorLookup[ndx + HLINE_COLOR]; dest = w->frameBuffer + vpos * w->width; ginfo("dest=%p pixel=0x%06lx\n", dest, pixel); for (i = 0; i < w->width; i++) { *dest++ = pixel; } /* Paint the vertical line */ pixel = w->colorLookup[ndx + HLINE_COLOR]; dest = w->frameBuffer + hpos; ginfo("dest=%p pixel=0x%06lx\n", dest, pixel); for (i = 0; i < w->height; i++) { *dest = pixel; dest += w->width; } } } /**************************************************************************** * Function: tcl_paint_grid * Description: ***************************************************************************/ void tcl_paint_grid(tcl_window_t *w) { dev_pixel_t *dest; dev_pixel_t pixel; int ndx = tcl_color_index(w); int hoffset, hpos, haccum; int voffset, vpos, vaccum; int gridmask; int i; ginfo("plane=%d ndx=%d\n", w->plane, ndx); /* Horizontal and vertical positions will depend on which plane is selected. */ switch (w->plane) { default: case EDITPLANE_X: hoffset = g_coord_offset[EDITPLANE_Y]; voffset = g_view_size - g_coord_offset[EDITPLANE_Z] - 1; break; case EDITPLANE_Y: hoffset = g_coord_offset[EDITPLANE_X]; voffset = g_view_size - g_coord_offset[EDITPLANE_Z] - 1; break; case EDITPLANE_Z: hoffset = g_coord_offset[EDITPLANE_X]; voffset = g_coord_offset[EDITPLANE_Y]; break; } /* This is the color of the grid */ pixel = w->colorLookup[ndx + GRID_COLOR]; /* Paint the horizontal grid lines */ gridmask = g_grid_step - 1; vaccum = ((voffset + gridmask) & ~gridmask) - voffset; vpos = (vaccum * w->height) / g_view_size; do { /* Paint one horizontal grid line */ dest = w->frameBuffer + vpos * w->width; for (i = 0; i < w->width; i++) { *dest++ = pixel; } /* Scale the next grid position onto the display */ vaccum += g_grid_step; vpos = (vaccum * w->height) / g_view_size; } while (vpos < w->height); /* Paint the vertical grid lines */ /* Force the starting offsets to lie on a grid line */ haccum = ((hoffset + gridmask) & ~gridmask) - hoffset; hpos = (haccum * w->width) / g_view_size; do { /* Paint one vertical grid line */ dest = w->frameBuffer + hpos; for (i = 0; i < w->height; i++) { *dest = pixel; dest += w->width; } /* Scale the next grid position onto the display */ haccum += g_grid_step; hpos = (haccum * w->width) / g_view_size; } while (hpos < w->width); } /**************************************************************************** * Function: tcl_paint_rectangles * Description: ***************************************************************************/ void tcl_paint_rectangles(tcl_window_t *w) { rect_list_t *head, *vhead, *hhead; rect_list_t *list; rect_data_t *ptr; dev_pixel_t pixel; int ndx = tcl_color_index(w); int hoffset, voffset; int hplane, vplane; int pos; /* Select the plane lists and plane position for the current window */ switch (w->plane) { default: case EDITPLANE_X: pos = g_plane_position[EDITPLANE_X]; hplane = EDITPLANE_Y; vplane = EDITPLANE_Z; head = g_xplane_list.head; hhead = g_yplane_list.head; vhead = g_zplane_list.head; break; case EDITPLANE_Y: pos = g_plane_position[EDITPLANE_Y]; hplane = EDITPLANE_X; vplane = EDITPLANE_Z; head = g_yplane_list.head; hhead = g_xplane_list.head; vhead = g_zplane_list.head; break; case EDITPLANE_Z: pos = g_plane_position[EDITPLANE_Z]; hplane = EDITPLANE_X; vplane = EDITPLANE_Y; head = g_zplane_list.head; hhead = g_xplane_list.head; vhead = g_yplane_list.head; break; } hoffset = g_coord_offset[hplane]; voffset = g_coord_offset[vplane]; /* Display the rectangles which are in the viewing plane */ pixel = w->colorLookup[ndx + NRECT_COLOR]; for (list = head; (list); list = list->flink) { ptr = &list->d; /* We only want the rectangles which lie on the current display level */ if (ptr->plane == pos) { tcl_paint_coplanar_rectangle(w, ptr, hoffset, voffset, pixel); } } /* Are we currently editting a new plane that is not yet in the list? It it * is the same as the display plane, then we will want to display that as * well. */ if ((g_edit_mode == EDITMODE_NEW) && (g_edit_plane == w->plane) && (g_edit_rect.plane == pos)) { pixel = w->colorLookup[ndx + SRECT_COLOR]; tcl_paint_coplanar_rectangle(w, &g_edit_rect, hoffset, voffset, pixel); } /* Display the rectangles which are orthogonal and "horizontal" with respect * to the viewing plane. * * Process every plane in the vertical axis (these will be horizontal) This * will by the Z plane for every viewing plane except EDITPLANE_Z where it * will be the Y plane */ pixel = w->colorLookup[ndx + BRECT_COLOR]; for (list = vhead; (list); list = list->flink) { ptr = &list->d; /* Search the plane list for every place whose "level" component includes * the current map level. */ if (tcl_check_horizontal_rectangle(w, ptr, pos)) { tcl_paint_horizontal_rectangle(w, ptr, hoffset, voffset, pixel); } } /* Are we currently editting a new plane that is not yet in the list? */ if ((g_edit_mode == EDITMODE_NEW) && (g_edit_plane == vplane)) { ptr = &g_edit_rect; if (tcl_check_horizontal_rectangle(w, ptr, pos)) { pixel = w->colorLookup[ndx + SRECT_COLOR]; tcl_paint_horizontal_rectangle(w, ptr, hoffset, voffset, pixel); } } /* Display the rectangles which are orthogonal and "vertical" with respect to * the viewing plane. * * Process every plane in the horizontal axis (these will be vertical) This * will by the X plane for every viewing plane except EDITPLANE_X where it * will be the Y plane. */ pixel = w->colorLookup[ndx + BRECT_COLOR]; for (list = hhead; (list); list = list->flink) { ptr = &list->d; /* Search the plane list for every place whose "level" component includes * the current map level. */ if (tcl_check_vertical_rectangle(w, ptr, pos)) { tcl_paint_vertical_rectangle(w, &list->d, hoffset, voffset, pixel); } } /* Are we currently editting a new plane that is not yet in the list? */ if ((g_edit_mode == EDITMODE_NEW) && (g_edit_plane == hplane)) { ptr = &g_edit_rect; if (tcl_check_vertical_rectangle(w, ptr, pos)) { pixel = w->colorLookup[ndx + SRECT_COLOR]; tcl_paint_vertical_rectangle(w, ptr, hoffset, voffset, pixel); } } }