#help_index "Graphics/Mesh" #define MESH_WORKSPACE_SIZE 4000 #define VF_SEL 1 #define VF_COPIED 2 #define VF_IGNORE 4 class CMeshEdVertex { CMeshEdVertex *next, *last, *copy; U0 start; CD3I32 p; //World coordinates of the point. U0 end; CD3I32 p0, pt; //Transformed coordinates. (Screen) I32 num, flags; }; #define TF_SEL 1 #define TF_COPIED 2 class CMeshEdTri { CMeshEdTri *next, *last; U0 start; CMeshTri mt; U0 end; I32 cpu_num, flags; //Draw different tris with different cores. CMeshEdVertex *t[3]; }; class CMeshFrame { I64 mouse_z, thickness; //Mouse Z-coordinate I64 ed_mode, cx, cy; CColorROPU32 cur_color; Bool grid_on, flip_y, sel_rect, vertex_on, closed, pad[3]; I64 mp_not_done_flags; //Used for multiprocessing signaling. F64 view_scale; CDC *dc; I32 *depth_buf; I64 *w2s, *s2w; //Screen-to-world and world-to-screen transform matrices. I64 vertex_count, tri_count; //Set by MeshSize CMeshEdVertex vertex_head, *cur_vertex, *chain_pred; CMeshEdTri tri_head, *cur_tri; I64 x1, y1, x2, y2, cur_snap; }; CMeshEdVertex *MeshVertexNew(CMeshFrame *e, I64 x, I64 y, I64 z) { CMeshEdVertex *tmpv = CAlloc(sizeof(CMeshEdVertex)); tmpv->p.x = x; tmpv->p.y = y; tmpv->p.z = z; QueueInsert(tmpv, e->vertex_head.last); return tmpv; } CMeshEdTri *MeshTriNew(CMeshFrame *e, CColorROPU32 color, CMeshEdVertex *v1, CMeshEdVertex *v2, CMeshEdVertex *v3) { static I64 cpu_num = 0; CMeshEdTri *tmpt = CAlloc(sizeof(CMeshEdTri)); tmpt->cpu_num = cpu_num++ % mp_count; tmpt->mt.color = color; tmpt->t[0] = v1; tmpt->t[1] = v2; tmpt->t[2] = v3; QueueInsert(tmpt, e->tri_head.last); return tmpt; } CMeshEdVertex *MeshVertexFindScrPt(CMeshFrame *e, I64 x, I64 y) {//Screen coordinates CMeshEdVertex *res = NULL, *tmpv = e->vertex_head.next; I64 dd, dz, best_dd = I64_MAX, best_dz = I64_MAX; while (tmpv != &e->vertex_head) { if (!(tmpv->flags & VF_IGNORE)) { dd = SqrI64(x - tmpv->pt.x) + SqrI64(y - tmpv->pt.y); dz = AbsI64(e->mouse_z - tmpv->p.z); if (dd < best_dd || dd == best_dd && dz < best_dz) { res = tmpv; best_dd = dd; best_dz = dz; } } tmpv = tmpv->next; } return res; } CMeshEdVertex *MeshVertexFindNum(CMeshFrame *haystack_e, I64 needle_num) { CMeshEdVertex *tmpv = haystack_e->vertex_head.next; while (tmpv != &haystack_e->vertex_head) { if (tmpv->num == needle_num) return tmpv; tmpv = tmpv->next; } return NULL; } U0 MeshTriDel(CMeshFrame *e, CMeshEdTri *tmpt) { if (tmpt) { if (tmpt == e->cur_tri) e->cur_tri = NULL; QueueRemove(tmpt); Free(tmpt); } } U0 MeshVertexDel(CMeshFrame *e, CMeshEdVertex *tmpv) { I64 i; CMeshEdTri *tmpt, *tmpt1; if (tmpv) { tmpt = e->tri_head.next; while (tmpt != &e->tri_head) { tmpt1 = tmpt->next; for (i = 0; i < 3; i++) if (tmpt->t[i] == tmpv) break; if (i < 3) MeshTriDel(e, tmpt); tmpt = tmpt1; } if (tmpv == e->cur_vertex) e->cur_vertex = NULL; if (tmpv == e->chain_pred) e->chain_pred = NULL; QueueRemove(tmpv); Free(tmpv); } } U0 MeshFence(CMeshFrame *e) { CMeshEdVertex *tmpv, *tmpv1, *tmpv_last = NULL, *tmpv1_last = NULL, *start = e->chain_pred->next, *end = e->vertex_head.last; tmpv = start; while (TRUE) { tmpv1 = MeshVertexNew(e, tmpv->p.x, tmpv->p.y, tmpv->p.z + e->thickness); if (tmpv_last) { MeshTriNew(e, e->cur_color, tmpv_last, tmpv, tmpv1); MeshTriNew(e, e->cur_color, tmpv1, tmpv1_last, tmpv_last); } tmpv_last = tmpv; tmpv1_last = tmpv1; if (tmpv == end) break; tmpv = tmpv->next; } if (e->closed && tmpv_last) { MeshTriNew(e, e->cur_color, tmpv_last, start, end->next); MeshTriNew(e, e->cur_color, end->next, tmpv1_last, tmpv_last); } } U0 MeshPolygon(CMeshFrame *e, CMeshEdVertex *start, CMeshEdVertex *end, Bool rev) { CMeshEdVertex *tmpv, *tmpv1; if (start != end) { tmpv = start; tmpv1 = tmpv->next; while (tmpv1 != end) { if (rev) MeshTriNew(e, e->cur_color, tmpv1, tmpv, end); else MeshTriNew(e, e->cur_color, tmpv, tmpv1, end); tmpv = tmpv->next; tmpv1 = tmpv1->next; } } } U0 MeshPrism(CMeshFrame *e) { CMeshEdVertex *start = e->chain_pred->next, *end = e->vertex_head.last; MeshFence(e); MeshPolygon(e, start, end, FALSE); MeshPolygon(e, end->next, e->vertex_head.last, TRUE); } U0 MeshVertexSelAll(CMeshFrame *e, Bool val) { CMeshEdVertex *tmpv = e->vertex_head.next; while (tmpv != &e->vertex_head) { if (val) tmpv->flags |= VF_SEL; else tmpv->flags &= ~VF_SEL; tmpv = tmpv->next; } } U0 MeshTriSelAll(CMeshFrame *e, Bool val) { CMeshEdTri *tmpt = e->tri_head.next; while (tmpt != &e->tri_head) { if (val) tmpt->flags |= TF_SEL; else tmpt->flags &= ~TF_SEL; tmpt = tmpt->next; } } U0 MeshVertexIgnoreSet(CMeshFrame *e, Bool val) { CMeshEdVertex *tmpv = e->vertex_head.next; while (tmpv != &e->vertex_head) { tmpv->flags &= ~VF_IGNORE; if (tmpv->flags & VF_SEL && val) tmpv->flags |= VF_IGNORE; tmpv = tmpv->next; } } U0 MeshP0Capture(CMeshFrame *e) { CMeshEdVertex *tmpv = e->vertex_head.next; while (tmpv != &e->vertex_head) { MemCopy(&tmpv->p0, &tmpv->p, sizeof(CD3I32)); tmpv = tmpv->next; } } U0 MeshP0Offset(CMeshFrame *e, I64 dx, I64 dy, I64 dz) { CMeshEdVertex *tmpv = e->vertex_head.next; while (tmpv != &e->vertex_head) { if (tmpv->flags & VF_SEL) { tmpv->p.x = tmpv->p0.x + dx; tmpv->p.y = tmpv->p0.y + dy; tmpv->p.z = tmpv->p0.z + dz; } tmpv = tmpv->next; } } #define SEL_MESH_EQU 0 #define SEL_MESH_OR 1 #define SEL_MESH_AND 2 U0 MeshVertexSelRect(CMeshFrame *e, I64 sel_mode, I64 x1, I64 x2, I64 y1, I64 y2) { CMeshEdVertex *tmpv = e->vertex_head.next; if (x1 > x2) SwapI64(&x1, &x2); if (y1 > y2) SwapI64(&y1, &y2); while (tmpv != &e->vertex_head) { if (x1 <= tmpv->pt.x <= x2 && y1 <= tmpv->pt.y <= y2) { if (sel_mode == SEL_MESH_AND) tmpv->flags &= ~VF_SEL; else tmpv->flags |= VF_SEL; } else if (sel_mode == SEL_MESH_EQU) tmpv->flags &= ~VF_SEL; tmpv = tmpv->next; } } U0 MeshTriSelRect(CMeshFrame *e, I64 sel_mode, I64 x1, I64 x2, I64 y1, I64 y2) { CMeshEdTri *tmpt = e->tri_head.next; if (x1 > x2) SwapI64(&x1, &x2); if (y1 > y2) SwapI64(&y1, &y2); while (tmpt != &e->tri_head) { if (x1 <= tmpt->t[0]->pt.x <= x2 && y1 <= tmpt->t[0]->pt.y <= y2 && x1 <= tmpt->t[1]->pt.x <= x2 && y1 <= tmpt->t[1]->pt.y <= y2 && x1 <= tmpt->t[2]->pt.x <= x2 && y1 <= tmpt->t[2]->pt.y <= y2) { if (sel_mode == SEL_MESH_AND) tmpt->flags &= ~TF_SEL; else tmpt->flags |= TF_SEL; } else { if (sel_mode == SEL_MESH_EQU) tmpt->flags &= ~TF_SEL; else if (sel_mode == SEL_MESH_AND) { if ( x1 <= tmpt->t[0]->pt.x <= x2 && y1 <= tmpt->t[0]->pt.y <= y2 || x1 <= tmpt->t[1]->pt.x <= x2 && y1 <= tmpt->t[1]->pt.y <= y2 || x1 <= tmpt->t[2]->pt.x <= x2 && y1 <= tmpt->t[2]->pt.y <= y2) tmpt->flags &= ~TF_SEL; } } tmpt = tmpt->next; } } I64 MeshSelCount(CMeshFrame *e) { I64 res = 0; CMeshEdVertex *tmpv = e->vertex_head.next; CMeshEdTri *tmpt = e->tri_head.next; while (tmpv != &e->vertex_head) { if (tmpv->flags & VF_SEL) res++; tmpv = tmpv->next; } while (tmpt != &e->tri_head) { if (tmpt->flags & TF_SEL) res++; tmpt = tmpt->next; } return res; } U0 MeshSwapAxes(CMeshFrame *e, I64 o1, I64 o2) { Bool unsel; CMeshEdVertex *tmpv = e->vertex_head.next; if (!MeshSelCount(e)) { MeshVertexSelAll(e, TRUE); unsel = TRUE; } else unsel = FALSE; while (tmpv != &e->vertex_head) { if (tmpv->flags & VF_SEL) SwapU32((&tmpv->p)(U8 *) + o1, (&tmpv->p)(U8 *) + o2); tmpv = tmpv->next; } if (unsel) MeshVertexSelAll(e, FALSE); } U0 MeshInvertAxis(CMeshFrame *e, I64 o) { Bool unsel; CMeshEdVertex *tmpv = e->vertex_head.next; if (!MeshSelCount(e)) { MeshVertexSelAll(e, TRUE); unsel = TRUE; } else unsel = FALSE; while (tmpv != &e->vertex_head) { if (tmpv->flags & VF_SEL) *((&tmpv->p)(U8 *) + o)(I32 *) = -*((&tmpv->p)(U8 *) + o)(I32 *); tmpv = tmpv->next; } if (unsel) MeshVertexSelAll(e, FALSE); } U0 MeshTransformSel(CMeshFrame *e) { Bool unsel; I64 r[16], x, y, z; CMeshEdVertex *tmpv = e->vertex_head.next; if (PopUpTransform(r)) { if (!MeshSelCount(e)) { MeshVertexSelAll(e, TRUE); unsel = TRUE; } else unsel = FALSE; while (tmpv != &e->vertex_head) { if (tmpv->flags & VF_SEL) { x = tmpv->p.x; y = tmpv->p.y; z = tmpv->p.z; Mat4x4MulXYZ(r, &x, &y, &z); tmpv->p.x = x; tmpv->p.y = y; tmpv->p.z = z; } tmpv = tmpv->next; } if (unsel) MeshVertexSelAll(e, FALSE); } } U0 MeshColorTris(CMeshFrame *e) { Bool unsel; CMeshEdTri *tmpt = e->tri_head.next; if (!MeshSelCount(e)) { MeshTriSelAll(e, TRUE); unsel = TRUE; } else unsel = FALSE; while (tmpt != &e->tri_head) { if (tmpt->flags & TF_SEL) tmpt->mt.color = e->cur_color; tmpt = tmpt->next; } if (unsel) MeshTriSelAll(e, FALSE); } U0 MeshRevTris(CMeshFrame *e) { Bool unsel; CMeshEdTri *tmpt = e->tri_head.next; if (!MeshSelCount(e)) { MeshTriSelAll(e, TRUE); unsel = TRUE; } else unsel = FALSE; while (tmpt != &e->tri_head) { if (tmpt->flags & TF_SEL) SwapI64(&tmpt->t[1], &tmpt->t[2]); tmpt = tmpt->next; } if (unsel) MeshTriSelAll(e, FALSE); } U0 MeshRecalcCxCy(CTask *task, CMeshFrame *e) { e->cx = RoundI64(task->pix_width / 2 - task->horz_scroll.pos, e->cur_snap); e->cy = RoundI64(task->pix_height / 2 - task->vert_scroll.pos, e->cur_snap); } U0 MeshCurSnap(CMeshFrame *e) { I64 x1, y1, z1, x2, y2, z2; if (e->w2s) { x1 = e->cur_snap << 16; y1 = 0; z1 = 0; Mat4x4MulXYZ(e->w2s, &x1, &y1, &z1); x2 = 0; y2 = e->cur_snap << 16; z2 = 0; Mat4x4MulXYZ(e->w2s, &x2, &y2, &z2); mouse_grid.x = Max(1, MaxI64(x1, x2) >> 16); mouse_grid.y = Max(1, MaxI64(y1, y2) >> 16); mouse_grid.z = Min(mouse_grid.x, mouse_grid.y); } } U0 MeshScaleZoom(CMeshFrame *e, F64 scale) { CTask *task = Fs; I64 x = mouse.pos.x - task->pix_left - task->scroll_x - task->pix_width / 2, y = mouse.pos.y - task->pix_top - task->scroll_y - task->pix_height / 2; task->horz_scroll.pos *= scale; task->vert_scroll.pos *= scale; task->horz_scroll.pos += scale * x - x; task->vert_scroll.pos += scale * y - y; e->view_scale *= scale; MeshRecalcCxCy(task, e); MeshCurSnap(e); } U0 MPDrawIt(CMeshFrame *e) {//Multiprocessing draw it, called by each core. //Makes a copy of e->dc so we can change dc->color member and stuff. CDC *dc = DCAlias(e->dc, e->dc->win_task); CMeshEdTri *tmpt = e->tri_head.next; I64 i, *old_r = dc->r; //DCAlias() allocs a new identity rotation matrix. //We want e->dc's rotation matrix. dc->r = e->dc->r; dc->depth_buf = e->depth_buf; MemCopy(&dc->ls, &e->dc->ls, sizeof(CD3I32)); //... and translation (shift) vals. dc->x = e->dc->x; dc->y = e->dc->y; dc->z = e->dc->z; dc->flags |= DCF_TRANSFORMATION; if (e->grid_on) //Draw grid with different cores. for (i = -500 + 25 * Gs->num; i <= 500; i += 25 * mp_count) { if (i) { dc->color = DKGRAY; GrLine3(dc, i, -500, 0, i, 500, 0); dc->color = LTGRAY; GrLine3(dc, -500, i, 0, 500, i, 0); } } if (!Gs->num) { dc->color = RED; //Y-Axis red GrLine3(dc, 0, 0, 0, 0, 500, 0); dc->color = ROPF_DITHER + RED; //Y-Axis red GrLine3(dc, 0, -500, 0, 0, 0, 0); dc->color = YELLOW; //X-Axis yellow GrLine3(dc, 0, 0, 0, 500, 0, 0); dc->color = ROPF_DITHER + YELLOW; //X-Axis yellow GrLine3(dc, -500, 0, 0, 0, 0, 0); dc->color = GREEN; //Z-Axis green GrLine3(dc, 0, 0, 0, 0, 0, 500); dc->color = ROPF_DITHER + GREEN; //Z-Axis green GrLine3(dc, 0, 0, -500, 0, 0, 0); } while (tmpt != &e->tri_head) { if (tmpt->cpu_num == Gs->num) { if (tmpt->flags & TF_SEL) { if (Blink) dc->color = ROPF_DITHER + WHITE << 16 + RED; else dc->color = ROPF_DITHER + RED << 16 + WHITE; GrFillTri0(dc, &tmpt->t[0]->pt, &tmpt->t[1]->pt, &tmpt->t[2]->pt); } else { (*dc->lighting)(dc, &tmpt->t[0]->pt, &tmpt->t[1]->pt, &tmpt->t[2]->pt, tmpt->mt.color); GrFillTri0(dc, &tmpt->t[0]->pt, &tmpt->t[1]->pt, &tmpt->t[2]->pt); } } tmpt = tmpt->next; } dc->r = old_r; //e->dc's depth buf was copied but we don't want it freed during DCDel(). dc->depth_buf = NULL; DCDel(dc); LBtr(&e->mp_not_done_flags, Gs->num); } I64 *MeshW2S(CMeshFrame *e, CTask *task) {//World to screen coordinate transform matrix. CCtrl *c = CtrlFindUnique(task, CTRLT_VIEWING_ANGLES); CViewAngles *s = c->state; I64 *r = Mat4x4IdentNew(task); Mat4x4Scale(r, e->view_scale); Mat4x4RotZ(r, s->az); Mat4x4RotY(r, s->ay); if (e->flip_y) Mat4x4RotX(r, s->ax); else Mat4x4RotX(r, s->ax + pi); return r; } I64 *MeshS2W(CMeshFrame *e, CTask *task) {//Screen to world coordinate transform matrix. CCtrl *c = CtrlFindUnique(task, CTRLT_VIEWING_ANGLES); CViewAngles *s = c->state; I64 *r = Mat4x4IdentNew(task); if (e->flip_y) Mat4x4RotX(r, -s->ax); else Mat4x4RotX(r, -(s->ax + pi)); Mat4x4RotY(r, -s->ay); Mat4x4RotZ(r, -s->az); Mat4x4Scale(r, 1 / e->view_scale); return r; } I64 *MeshSetW2S(CMeshFrame *e, CTask *task) { Free(e->w2s); e->w2s = MeshW2S(e, task); Free(e->s2w); e->s2w = MeshS2W(e, task); //returned matrix is assigned to dc->r and will be freed by DCDel(). return Mat4x4New(e->w2s, task); } U0 MeshCursorW(CMeshFrame *e, CTask *task, I64 *_x, I64 *_y, I64 *_z) { I64 x_shadow, y_shadow, z_shadow, xc = mouse.pos.x - task->pix_left - task->scroll_x - e->cx, yc = mouse.pos.y - task->pix_top - task->scroll_y - e->cy, zc = 0, x = 0, y = 0, z = e->mouse_z, i, x2, y2, z2; Mat4x4MulXYZ(e->w2s, &x, &y, &z); //screen of Z vect //Converges onto a solution for zc, an unknown. for (i = 0; i < 128; i++) { x_shadow = xc - x; //Shadow of mouse cursor on xy plane y_shadow = yc - y; z_shadow = zc - z; Mat4x4MulXYZ(e->s2w, &x_shadow, &y_shadow, &z_shadow); x2 = 0; y2 = 0; z2 = -z_shadow; Mat4x4MulXYZ(e->w2s, &x2, &y2, &z2); zc += Round(Sqrt(x2 * x2 + y2 * y2 + z2 * z2)) * SignI64(z2); } x = xc - x; y = yc - y; z = zc - z; Mat4x4MulXYZ(e->s2w, &x, &y, &z); x = RoundI64(x, e->cur_snap); y = RoundI64(y, e->cur_snap); z = RoundI64(e->mouse_z, e->cur_snap); *_x = x; *_y = y; *_z = z; } CMeshEdVertex sys_clip_vertex_head; CMeshEdTri sys_clip_tri_head; U0 MeshClipInit() { QueueInit(&sys_clip_vertex_head); QueueInit(&sys_clip_tri_head); } U0 MeshClipReset() { QueueDel(&sys_clip_vertex_head, TRUE); QueueDel(&sys_clip_tri_head, TRUE); MeshClipInit; } U0 MeshClipCopy(CMeshFrame *e) { CMeshEdVertex *tmpv = e->vertex_head.next, *tmpv2; CMeshEdTri *tmpt = e->tri_head.next, *tmpt2; MeshClipReset; while (tmpv != &e->vertex_head) { if (tmpv->flags & VF_SEL) { tmpv->copy = tmpv2 = SysCAlloc(sizeof(CMeshEdVertex)); MemCopy(&tmpv2->p, &tmpv->p, sizeof(CD3I32)); QueueInsert(tmpv2, sys_clip_vertex_head.last); tmpv->flags |= VF_COPIED; tmpv->flags &= ~VF_SEL; } else { tmpv->copy = NULL; tmpv->flags &= ~(VF_COPIED | VF_SEL); } tmpv = tmpv->next; } while (tmpt != &e->tri_head) { if (tmpt->flags & TF_SEL && tmpt->t[0]->copy && tmpt->t[1]->copy && tmpt->t[2]->copy) { tmpt2 = SysCAlloc(sizeof(CMeshEdTri)); tmpt2->t[0] = tmpt->t[0]->copy; tmpt2->t[1] = tmpt->t[1]->copy; tmpt2->t[2] = tmpt->t[2]->copy; tmpt2->mt.color = tmpt->mt.color; QueueInsert(tmpt2, sys_clip_tri_head.last); tmpt->flags |= TF_COPIED; tmpt->flags &= ~TF_SEL; } else tmpt->flags &= ~(TF_COPIED|TF_SEL); tmpt = tmpt->next; } } U0 MeshClipCut(CMeshFrame *e) { CMeshEdVertex *tmpv = e->vertex_head.next, *tmpv1; CMeshEdTri *tmpt = e->tri_head.next, *tmpt1; MeshClipCopy(e); while (tmpt != &e->tri_head) { tmpt1 = tmpt->next; if (tmpt->flags & TF_COPIED) MeshTriDel(e, tmpt); tmpt = tmpt1; } while (tmpv != &e->vertex_head) { tmpv1 = tmpv->next; if (tmpv->flags & VF_COPIED) MeshVertexDel(e, tmpv); tmpv = tmpv1; } } U0 MeshClipDel(CMeshFrame *e) {//Technically not clip CMeshEdVertex *tmpv = e->vertex_head.next, *tmpv1; CMeshEdTri *tmpt = e->tri_head.next, *tmpt1; while (tmpt != &e->tri_head) { tmpt1 = tmpt->next; if (tmpt->flags & TF_SEL) MeshTriDel(e, tmpt); tmpt = tmpt1; } while (tmpv != &e->vertex_head) { tmpv1 = tmpv->next; if (tmpv->flags & VF_SEL) MeshVertexDel(e, tmpv); tmpv = tmpv1; } } U0 MeshClipPaste(CMeshFrame *e) { CMeshEdVertex *tmpv2 = sys_clip_vertex_head.next, *tmpv; CMeshEdTri *tmpt2 = sys_clip_tri_head.next, *tmpt; MeshVertexSelAll(e, FALSE); MeshTriSelAll(e, FALSE); while (tmpv2 != &sys_clip_vertex_head) { tmpv2->copy = tmpv = CAlloc(sizeof(CMeshEdVertex)); MemCopy(&tmpv->p, &tmpv2->p, sizeof(CD3I32)); QueueInsert(tmpv, e->vertex_head.last); tmpv->flags |= VF_SEL; tmpv2 = tmpv2->next; } while (tmpt2 != &sys_clip_tri_head) { tmpt = MeshTriNew(e, tmpt2->mt.color, tmpt2->t[0]->copy, tmpt2->t[1]->copy, tmpt2->t[2]->copy); tmpt->flags |= TF_SEL; tmpt2 = tmpt2->next; } } MeshClipInit; U0 DrawIt(CTask *task, CDC *dc) { CMeshFrame *e = FramePtr("CMeshFrame", task); CCtrl *c = CtrlFindUnique(task, CTRLT_VIEWING_ANGLES); F64 d; I64 i, x, y, z; CMeshEdVertex *tmpv; task->horz_scroll.min = -(MESH_WORKSPACE_SIZE - task->pix_width) / 2; task->horz_scroll.max = (MESH_WORKSPACE_SIZE - task->pix_width) / 2; task->vert_scroll.min = -(MESH_WORKSPACE_SIZE - task->pix_height) / 2; task->vert_scroll.max = (MESH_WORKSPACE_SIZE - task->pix_height) / 2; TaskDerivedValsUpdate(task); MeshRecalcCxCy(task, e); dc->flags |= DCF_TRANSFORMATION; Free(dc->r); //Set rotmat doesn't free old dc->r matrix. DCMat4x4Set(dc, MeshSetW2S(e, task)); dc->x = e->cx; dc->y = e->cy; //z-vals less than zero are in front of screen and not drawn. //we want to shift all Z-vals into a drawable range. //GR_Z_ALL is set to half of the Z-range which is an I32. dc->z = GR_Z_ALL; //Light source set to mouse. MeshCursorW(e, task, &x, &y, &z); dc->ls.x = x; dc->ls.y = y; dc->ls.z = z; d = 1 << 16 / D3I32Norm(&dc->ls); //Light source normalized to 65536. dc->ls.x *= d; dc->ls.y *= d; dc->ls.z *= d; DCDepthBufAlloc(dc); tmpv = e->vertex_head.next; while (tmpv != &e->vertex_head) { x = tmpv->p.x; y = tmpv->p.y; z = tmpv->p.z; (*dc->transform)(dc, &x, &y, &z); tmpv->pt.x = x; tmpv->pt.y = y; tmpv->pt.z = z; tmpv = tmpv->next; } e->mp_not_done_flags = 1 << mp_count - 1; //Issue jobs to all cores. e->dc = dc; e->depth_buf = dc->depth_buf; for (i = 0; i < mp_count; i++) JobQueue(&MPDrawIt, e, i); tmpv = e->vertex_head.next; while (tmpv != &e->vertex_head) { x = tmpv->pt.x; y = tmpv->pt.y; z = tmpv->pt.z; if (e->vertex_on) { if (Blink(10)) //This blinks at 10 Hz. dc->color = ROPF_DITHER + BLACK << 16 + WHITE; else dc->color = ROPF_DITHER + WHITE << 16 + BLACK; GrLine(dc, x - 3, y - 3, x + 3, y + 3); GrLine(dc, x - 3, y + 3, x + 3, y - 3); } if (tmpv->flags & VF_SEL) { if (e->ed_mode == 't') { if (Blink(10)) //This blinks at 10 Hz. dc->color = ROPF_DITHER + e->cur_color.c0.color << 16 + e->cur_color.c0.color ^ 8; else dc->color = ROPF_DITHER + (e->cur_color.c0.color ^ 8) << 16 + e->cur_color.c0.color; } else { if (Blink) dc->color = ROPF_DITHER + RED << 16 + WHITE; else dc->color = ROPF_DITHER + WHITE << 16 + RED; } GrCircle(dc, x, y, 3); } tmpv = tmpv->next; } if (CtrlInside(c, mouse.presnap.x, mouse.presnap.y) || winmgr.show_menu) { GridInit; task->win_inhibit = WIF_SELF_DOC; } else { MeshCurSnap(e); task->win_inhibit = WIG_TASK_DEFAULT | WIF_SELF_DOC - WIF_SELF_FOCUS - WIF_SELF_BORDER - WIF_SELF_CTRLS - WIF_FOCUS_TASK_MENU - WIF_SELF_GRAB_SCROLL; } MeshCursorW(e, task, &x, &y, &z); if (z < 0) dc->color = ROP_XOR + RED ^ TRANSPARENT; else dc->color = ROP_XOR + TRANSPARENT; GrPrint(dc, 0, 0, "%6.3f%% (%d,%d,%d)", e->view_scale * 100, x, y, z); dc->thick = 1; dc->color &= 0xF; if (Blink(10)) dc->color ^= 0xF; GrLine3(dc, x, y, z, x, y, 0); if (e->sel_rect) { dc->flags &= ~DCF_TRANSFORMATION; dc->thick = 1; if (Blink) dc->color = ROPF_DITHER + RED << 16 + WHITE; else dc->color = ROPF_DITHER + WHITE << 16 + RED; GrBorder(dc, e->x1, e->y1, e->x2, e->y2); } //Wait for all cores to complete. while (e->mp_not_done_flags) Yield; } U0 MeshInit(CMeshFrame *e, Bool flip_y) { MemSet(e, 0, sizeof(CMeshFrame)); QueueInit(&e->vertex_head); QueueInit(&e->tri_head); e->ed_mode = 'v'; e->grid_on = TRUE; e->vertex_on = TRUE; e->mouse_z = 0; e->thickness = 25; e->closed = TRUE; e->view_scale = 1.0; e->w2s = NULL; e->s2w = NULL; e->cur_color = RED; e->cur_snap = 5; e->flip_y = flip_y; e->sel_rect = FALSE; e->cur_tri = NULL; e->cur_vertex = NULL; e->chain_pred = NULL; } U0 MeshLoad(CMeshFrame *e, U8 *src) { I64 i, j, x, y, z; CColorROPU32 color; CMeshEdVertex *tmpv, *va[3]; QueueInit(&e->vertex_head); QueueInit(&e->tri_head); e->vertex_count = *src(I32 *)++; e->tri_count = *src(I32 *)++; for (i = 0; i < e->vertex_count; i++) { x = *src(I32 *)++; y = *src(I32 *)++; z = *src(I32 *)++; tmpv = MeshVertexNew(e, x, y, z); tmpv->num = i; } for (i = 0; i < e->tri_count; i++) { color = *src(I32 *)++; for (j = 0; j < 3; j++) va[j] = MeshVertexFindNum(e, *src(I32 *)++); MeshTriNew(e, color, va[0], va[1], va[2]); } } I64 MeshSize(CMeshFrame *e) { I64 i; CMeshEdVertex *tmpv = e->vertex_head.next; CMeshEdTri *tmpt = e->tri_head.next; e->vertex_count = 0; while (tmpv != &e->vertex_head) { tmpv->num = e->vertex_count++; tmpv = tmpv->next; } e->tri_count = 0; while (tmpt != &e->tri_head) { e->tri_count++; for (i = 0; i < 3; i++) tmpt->mt.nums[i] = tmpt->t[i]->num; tmpt = tmpt->next; } return sizeof(I32) * 2 + (offset(CMeshEdVertex.end) - offset(CMeshEdVertex.start)) * e->vertex_count + (offset(CMeshEdTri.end) - offset(CMeshEdTri.start)) * e->tri_count; } I32 *MeshSave(CMeshFrame *e, I64 *_size=NULL) { I64 size = MeshSize(e); U8 *res = MAlloc(size), *dst = res; CMeshEdVertex *tmpv = e->vertex_head.next; CMeshEdTri *tmpt = e->tri_head.next; *dst(I32 *)++ = e->vertex_count; *dst(I32 *)++ = e->tri_count; e->vertex_count = 0; while (tmpv != &e->vertex_head) { MemCopy(dst, &tmpv->start, offset(CMeshEdVertex.end) -offset(CMeshEdVertex.start)); dst += offset(CMeshEdVertex.end) - offset(CMeshEdVertex.start); tmpv = tmpv->next; } e->tri_count = 0; while (tmpt != &e->tri_head) { MemCopy(dst, &tmpt->start, offset(CMeshEdTri.end) - offset(CMeshEdTri.start)); dst += offset(CMeshEdTri.end) - offset(CMeshEdTri.start); tmpt = tmpt->next; } if (_size) *_size = size; return res; } U0 MeshCleanUp(CMeshFrame *e) { QueueDel(&e->vertex_head, TRUE); QueueDel(&e->tri_head, TRUE); Free(e->w2s); Free(e->s2w); } U0 MeshUpdateMenu(CMeshFrame *e) { CMenuEntry *tmpse; if (tmpse = MenuEntryFind(Fs->cur_menu, "View/Grid")) tmpse->checked = ToBool(e->grid_on); if (tmpse = MenuEntryFind(Fs->cur_menu, "View/Vertex")) tmpse->checked = ToBool(e->vertex_on); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/PlaceVertex")) tmpse->checked = ToBool(e->ed_mode == 'v'); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/MoveVertex")) tmpse->checked = ToBool(e->ed_mode == 'm'); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/MoveVertexZ")) tmpse->checked = ToBool(e->ed_mode == 'M'); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/Triangle")) tmpse->checked = ToBool(e->ed_mode == 't'); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/Polygon")) tmpse->checked = ToBool(e->ed_mode == 'n'); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/Fence")) tmpse->checked = ToBool(e->ed_mode == 'f'); if (tmpse = MenuEntryFind(Fs->cur_menu, "Mode/Prism")) tmpse->checked = ToBool(e->ed_mode == 'p'); if (tmpse = MenuEntryFind(Fs->cur_menu, "View/FlipY")) tmpse->checked = ToBool(e->flip_y); } I32 *SpriteMeshEd(I32 *head=NULL, I64 *_size=NULL, Bool flip_y=FALSE) {/*Format for mesh: { I32 vertex_count; I32 tri_count; CD3I32 vertices[]; CMeshTri tris[]; } If head points to a mesh, it will load it. Returns a newly malloced mesh or NULL. See ::/Demo/Graphics/SpritePlot3D.CC. */ CCtrl *c = CtrlFindUnique(Fs, CTRLT_VIEWING_ANGLES); CViewAngles *s, *old_s; I64 i, message_code, sel_mode, arg1, arg2, make_tri_vertex_num = 0, x, y, z; CD3I32 p0a, p0b; CMeshEdVertex *va[3], *tmpv; Bool adjusting_z = FALSE, moving, save_and_exit, adjusting_camera_xy = FALSE, adjusting_camera_z = FALSE; CMeshFrame e; if (c) { old_s = MAlloc(sizeof(CViewAngles)); MemCopy(old_s, c->state, sizeof(CViewAngles)); } else { c = ViewAnglesNew; old_s = NULL; } s = c->state; s->sx = 0; s->sy = 0; s->sz = 0; s->cx = YELLOW; s->cy = RED; s->cz = GREEN; MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Edit {" " Delete(,,SC_DELETE);" " DelLast(,CH_BACKSPACE);" " Cut(,CH_CTRLX);" " Copy(,CH_CTRLC);" " Paste(,CH_CTRLV);" " SelectAll(,'A');" " UnSelectAll(,'U');" " SelectRect(,'a');" " UnSelectRect(,'u');" " OrSelectRect(,'o');" " JumpToZ(,'j');" " ResetColor(,'C');" " ReverseTri(,'r');" "}" "Mode {" " PlaceVertex(,'v');" " MoveVertex(,'m');" " MoveVertexZ(,'M');" " Triangle(,'t');" " Polygon(,'n');" " Fence(,'f');" " Prism(,'p');" "}" "Settings {" " Color(,'c');" " Snap(,'s');" "}" "View {" " ZoomIn(,'z');" " ZoomOut(,'Z');" " NullAngles(,'N');" " FlipY(,'y');" " Grid(,'g');" " Vertex(,'V');" " ToggleBorder(,CH_CTRLB);" "}" "Transforms {" " Transform(,'T');" " SwapXY(,'1');" " SwapXZ(,'2');" " SwapYZ(,'3');" " InvertX(,'4');" " InvertY(,'5');" " InvertZ(,'6');" " ReverseTri(,'R');" "}"); SettingsPush; //See SettingsPush AutoComplete; RegOneTimePopUp(ARf_MESH_ED, "$GREEN$Right Mouse$FG$: Hold and move to shift cursor z\n" "$GREEN$Shift + Right Mouse$FG$: Hold and move to rotate camera XY\n" "$GREEN$Alt + Right Mouse$FG$: Hold and move to rotate camera Z\n" "$GREEN$'j'$FG$: Jump cursor Z to nearest vertex's Z\n" "$GREEN$'v'$FG$: Place Vertex Mode\n" "$GREEN$'m'$FG$: Move Vertex Mode\n" "$GREEN$'M'$FG$: Move Vertex Z\n" "$GREEN$'t'$FG$: Form Triangle Mode\n" "$GREEN$'n'$FG$: Polygon Mode\n" "$GREEN$'f'$FG$: Fence Mode\n" "$GREEN$'p'$FG$: Prism Mode\n" "$GREEN$'c'$FG$: Set color\n" "$GREEN$'s'$FG$: Set snap\n" "\nSee menu at top of screen for more.\n"); Fs->win_inhibit = WIG_TASK_DEFAULT | WIF_SELF_DOC - WIF_SELF_FOCUS - WIF_SELF_BORDER - WIF_SELF_CTRLS - WIF_FOCUS_TASK_MENU - WIF_SELF_GRAB_SCROLL; Fs->horz_scroll.pos = 0; Fs->vert_scroll.pos = 0; MeshInit(&e, flip_y); if (head) MeshLoad(&e, head); FramePtrAdd("CMeshFrame", &e); Fs->draw_it = &DrawIt; MeshCurSnap(&e); MeshRecalcCxCy(Fs, &e); try {//In case of <CTRL-ALT-c> while (TRUE) { MeshUpdateMenu(&e); message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_MOVE | 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_L_DOWN| 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_R_UP); me_restart: switch (message_code) { case MESSAGE_KEY_DOWN: switch (arg1) { case 0: switch (arg2.u8[0]) { case SC_DELETE: if (arg2 & SCF_SHIFT) goto me_clip_cut; else { if (MeshSelCount(&e)) MeshClipDel(&e); else if (e.ed_mode != 't') MeshVertexDel(&e, MeshVertexFindScrPt(&e, mouse.presnap.x - Fs->pix_left - Fs->scroll_x, mouse.presnap.y - Fs->pix_top - Fs->scroll_y)); MeshVertexSelAll(&e, FALSE); MeshTriSelAll(&e, FALSE); make_tri_vertex_num = 0; } break; case SC_INS: if (arg2 & SCF_CTRL) goto me_clip_copy; else if (arg2 & SCF_SHIFT) goto me_clip_paste; } break; case CH_BACKSPACE: switch (e.ed_mode) { case 'n': case 'f': case 'p': case 'v': MeshVertexDel(&e, e.cur_vertex); break; case 't': if (make_tri_vertex_num) { MeshVertexSelAll(&e, FALSE); MeshTriSelAll(&e, FALSE); make_tri_vertex_num = 0; } else MeshTriDel(&e, e.cur_tri); break; } break; case 'f': case 'p': e.thickness = PopUpI64Get("Thickness (%d):", e.thickness); case 'n': if (arg1 == 'n' || arg1 == 'p') e.closed = TRUE; else e.closed = PopUpNoYes("Closed?\n"); me_chain: e.chain_pred = e.vertex_head.last; case 't': MeshVertexSelAll(&e, FALSE); MeshTriSelAll(&e, FALSE); case 'v': case 'm': case 'M': adjusting_z = FALSE; moving = FALSE; e.ed_mode = arg1; make_tri_vertex_num = 0; Sound; break; case 'T': MeshTransformSel(&e); break; case 'A': MeshTriSelAll(&e, TRUE); if (e.ed_mode != 't') MeshVertexSelAll(&e, TRUE); else MeshVertexSelAll(&e, FALSE); make_tri_vertex_num = 0; break; case 'U': MeshTriSelAll(&e, FALSE); MeshVertexSelAll(&e, FALSE); make_tri_vertex_num = 0; break; case 'a': case 'u': case 'o': if (arg1 == 'a') sel_mode = SEL_MESH_EQU; else if (arg1 == 'u') sel_mode = SEL_MESH_AND; else sel_mode = SEL_MESH_OR; if ((message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_R_UP)) != MESSAGE_MS_L_DOWN) { Beep; Beep; goto me_restart; } e.x1 = arg1; e.y1 = arg2; e.x2 = arg1; e.y2 = arg2; e.sel_rect = TRUE; while (TRUE) { message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_MOVE | 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_R_UP); if (message_code == MESSAGE_MS_MOVE) { e.x2 = arg1; e.y2 = arg2; } else if (message_code == MESSAGE_MS_L_UP) { e.x2 = arg1; e.y2 = arg2; break; } else { e.sel_rect = FALSE; Beep; Beep; goto me_restart; } } e.sel_rect = FALSE; MeshTriSelRect(&e, sel_mode, e.x1, e.x2, e.y1, e.y2); if (e.ed_mode != 't') MeshVertexSelRect(&e, sel_mode, e.x1, e.x2, e.y1, e.y2); else MeshVertexSelAll(&e, FALSE); make_tri_vertex_num = 0; break; case CH_CTRLB: WinBorder(Bt(&Fs->display_flags, DISPLAYf_NO_BORDER)); break; case CH_CTRLC: me_clip_copy: if (e.ed_mode == 't') { Beep; Beep; } else MeshClipCopy(&e); break; case CH_CTRLV: me_clip_paste: if (e.ed_mode == 't') { Beep; Beep; } else { MeshClipPaste(&e); e.ed_mode = 'm'; } break; case CH_CTRLX: me_clip_cut: if (e.ed_mode == 't') { Beep; Beep; } else MeshClipCut(&e); break; case CH_SHIFT_ESC: save_and_exit = FALSE; goto me_done; case CH_ESC: save_and_exit = TRUE; goto me_done; case 'z': MeshScaleZoom(&e, 1.5); break; case 'Z': MeshScaleZoom(&e, 1 / 1.5); break; case 'c': e.cur_color = PopUpColorLighting; break; case 's': i = PopUpRangeI64(1, 25, 1, "New Snap\n"); if (i >= 1) e.cur_snap = i; MeshCurSnap(&e); MeshRecalcCxCy(Fs, &e); break; case 'g': e.grid_on = !e.grid_on; break; case 'V': e.vertex_on = !e.vertex_on; break; case 'N': s->sx = s->sy = s->sz = 0; break; case 'y': e.flip_y = !e.flip_y; break; case 'j': if (moving) MeshVertexIgnoreSet(&e, TRUE); if (tmpv = MeshVertexFindScrPt(&e, mouse.pos.x - Fs->pix_left - Fs->scroll_x, mouse.pos.y - Fs->pix_top - Fs->scroll_y)) { Noise(25, 86, 110); e.mouse_z = RoundI64(tmpv->p.z, e.cur_snap); } else { Beep; Beep; e.mouse_z = 0; } MeshVertexIgnoreSet(&e, FALSE); if (moving) { MeshCursorW(&e, Fs, &x, &y, &z); if (adjusting_z) MeshP0Offset(&e, 0, 0, z - p0a.z); else MeshP0Offset(&e, x - p0a.x, y - p0a.y, z - p0a.z); p0a.x = x; p0a.y = y; p0a.z = z; MeshP0Capture(&e); } break; case '1': MeshSwapAxes(&e, offset(CD3I32.x), offset(CD3I32.y)); break; case '2': MeshSwapAxes(&e, offset(CD3I32.x), offset(CD3I32.z)); break; case '3': MeshSwapAxes(&e, offset(CD3I32.y), offset(CD3I32.z)); break; case '4': MeshInvertAxis(&e, offset(CD3I32.x)); break; case '5': MeshInvertAxis(&e, offset(CD3I32.y)); break; case '6': MeshInvertAxis(&e, offset(CD3I32.z)); break; case 'r': if (e.cur_tri) SwapI64(&e.cur_tri->t[1], &e.cur_tri->t[2]); break; case 'C': MeshColorTris(&e); break; case 'R': MeshRevTris(&e); break; } break; case MESSAGE_MS_L_DOWN: switch (e.ed_mode) { case 'm': if (!moving) { if (!MeshSelCount(&e) && (tmpv = MeshVertexFindScrPt(&e, arg1, arg2))) { tmpv->flags |= VF_SEL; e.mouse_z = RoundI64(tmpv->p.z, e.cur_snap); } if (MeshSelCount(&e)) { MeshCursorW(&e, Fs, &x, &y, &z); p0a.x = x; p0a.y = y; p0a.z = z; MeshP0Capture(&e); moving = TRUE; } } break; case 'M': if (!adjusting_z && !moving) { if (!MeshSelCount(&e) && (tmpv = MeshVertexFindScrPt(&e, arg1, arg2))) { tmpv->flags |= VF_SEL; e.mouse_z = RoundI64(tmpv->p.z, e.cur_snap); } if (MeshSelCount(&e)) { MeshCursorW(&e, Fs, &x, &y, &z); p0a.x = x; p0a.y = y; p0a.z = z; MeshP0Capture(&e); moving = TRUE; p0b.x = mouse.presnap.x; p0b.y = mouse.presnap.y; p0b.z = e.mouse_z; adjusting_z = TRUE; Sound(ClampI64(Freq2Ona(3 * e.mouse_z + 1500), 0, I8_MAX)); } } break; } break; case MESSAGE_MS_L_UP: switch (e.ed_mode) { case 'n': case 'f': case 'p': case 'v': Noise(25, 86, 110); MeshCursorW(&e, Fs, &x, &y, &z); e.cur_vertex = MeshVertexNew(&e, x, y, z); break; case 'm': case 'M': if (moving) { if (adjusting_z) { e.mouse_z = RoundI64(Sign(p0b.y - mouse.presnap.y) * Sqrt(Sqr(p0b.x - mouse.presnap.x) + Sqr(p0b.y - mouse.presnap.y)) + p0b.z, e.cur_snap); Sound; adjusting_z = FALSE; MeshCursorW(&e, Fs, &x, &y, &z); MeshP0Offset(&e, 0, 0, z - p0a.z); } else { MeshCursorW(&e, Fs, &x, &y, &z); MeshP0Offset(&e, x - p0a.x, y - p0a.y, z - p0a.z); } MeshTriSelAll(&e, FALSE); MeshVertexSelAll(&e, FALSE); moving = FALSE; } break; case 't': if (tmpv = MeshVertexFindScrPt(&e, arg1, arg2)) { for (i = 0; i < make_tri_vertex_num; i++) if (va[i] == tmpv) { Beep; Beep; break; } if (i == make_tri_vertex_num) { Noise(25, 86, 110); va[make_tri_vertex_num++] = tmpv; tmpv->flags |= VF_SEL; if (make_tri_vertex_num == 3) { e.cur_tri = MeshTriNew(&e, e.cur_color, va[0], va[1], va[2]); for (i = 0; i < make_tri_vertex_num; i++) va[i]->flags &= ~VF_SEL; make_tri_vertex_num = 0; } } } break; } break; case MESSAGE_MS_R_DOWN: if (Bt(kbd.down_bitmap, SC_SHIFT)) adjusting_camera_xy = TRUE; if (Bt(kbd.down_bitmap, SC_ALT)) adjusting_camera_z = TRUE; if (!adjusting_z && e.ed_mode != 'M' && (e.chain_pred == e.vertex_head.last || e.ed_mode != 'n' && e.ed_mode != 'f' && e.ed_mode != 'p') && !adjusting_camera_xy && !adjusting_camera_z) { if (moving) { MeshCursorW(&e, Fs, &x, &y, &z); MeshP0Offset(&e, x - p0a.x, y - p0a.y, z - p0a.z); p0a.x = x; p0a.y = y; p0a.z = z; MeshP0Capture(&e); } p0b.x = mouse.presnap.x; p0b.y = mouse.presnap.y; p0b.z = e.mouse_z; adjusting_z = TRUE; Sound(ClampI64(Freq2Ona(3 * e.mouse_z + 1500), 0, I8_MAX)); } break; case MESSAGE_MS_R_UP: adjusting_camera_xy = FALSE; adjusting_camera_z = FALSE; if (adjusting_z) { e.mouse_z = RoundI64(Sign(p0b.y - mouse.presnap.y) * Sqrt(Sqr(p0b.x - mouse.presnap.x) + Sqr(p0b.y - mouse.presnap.y)) + p0b.z, e.cur_snap); Sound; adjusting_z = FALSE; if (moving) { MeshCursorW(&e, Fs, &x, &y, &z); MeshP0Offset(&e, 0, 0, z - p0a.z); p0a.x = x; p0a.y = y; p0a.z = z; MeshP0Capture(&e); } } else if (e.ed_mode == 'n') { if (e.chain_pred && e.chain_pred != e.vertex_head.last) MeshPolygon(&e, e.chain_pred->next, e.vertex_head.last, FALSE); arg1 = e.ed_mode; goto me_chain; } else if (e.ed_mode == 'f') { if (e.chain_pred && e.chain_pred != e.vertex_head.last) MeshFence(&e); arg1 = e.ed_mode; goto me_chain; } else if (e.ed_mode == 'p') { if (e.chain_pred && e.chain_pred != e.vertex_head.last) MeshPrism(&e); arg1 = e.ed_mode; goto me_chain; } break; case MESSAGE_MS_MOVE: if (adjusting_camera_xy) { // In the editor, X and Y of mouse rotate around Y and X 3D axes. s->sx += mouse.presnap.y - mouse_last.presnap.y; if (s->sx < 0) s->sx = 360; // VIEWANGLES_RANGE else if (s->sx > 360) s->sx = 0; s->sy -= mouse.presnap.x - mouse_last.presnap.x; if (s->sy < 0) s->sy = 360; // VIEWANGLES_RANGE else if (s->sy > 360) s->sy = 0; } if (adjusting_camera_z) { // In the editor, X and Y of mouse rotates around Z 3D axis. s->sz += mouse.presnap.x - mouse_last.presnap.x; s->sz += mouse.presnap.y - mouse_last.presnap.y; if (s->sz < 0) s->sz = 360; // VIEWANGLES_RANGE else if (s->sz > 360) s->sz = 0; } if (adjusting_camera_xy || adjusting_camera_z) break; if (adjusting_z) { e.mouse_z = RoundI64(Sign(p0b.y - mouse.presnap.y) * Sqrt(Sqr(p0b.x - mouse.presnap.x) + Sqr(p0b.y - mouse.presnap.y)) + p0b.z, e.cur_snap); Sound(ClampI64(Freq2Ona(3 * e.mouse_z + 1500), 0, I8_MAX)); } if (moving) { MeshCursorW(&e, Fs, &x, &y, &z); if (adjusting_z) MeshP0Offset(&e, 0, 0, z - p0a.z); else MeshP0Offset(&e, x - p0a.x, y - p0a.y, z - p0a.z); p0a.x = x; p0a.y = y; p0a.z = z; MeshP0Capture(&e); } break; } } me_done: } catch Fs->catch_except = TRUE; SettingsPop; MenuPop; if (save_and_exit) head = MeshSave(&e, _size); else head = NULL; MeshCleanUp(&e); FramePtrDel("CMeshFrame"); if (old_s) { MemCopy(c->state, old_s, sizeof(CViewAngles)); Free(old_s); } else ViewAnglesDel; return head; }