diff --git a/radiant/patch.cpp b/radiant/patch.cpp index 221d3333..5b2622bb 100644 --- a/radiant/patch.cpp +++ b/radiant/patch.cpp @@ -1402,8 +1402,8 @@ void Patch::ConstructPrefab(const AABB& aabb, EPatchPrefab eType, int axis, std: } else if (eType == eXactCylinder) { - int n = 6; // n = number of segments - setDims(2 * n + 1, 3); + int n = (width - 1) / 2; // n = number of segments + setDims(width, height); // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); // vPos[1] = aabb.origin; @@ -1411,16 +1411,73 @@ void Patch::ConstructPrefab(const AABB& aabb, EPatchPrefab eType, int axis, std: int i, j; float f = 1 / cos(M_PI / n); - for(i = 0; i < 2*n+1; ++i) + for(i = 0; i < width; ++i) { - float angle = (M_PI * i) / n; - float x = vPos[1][0] + cos(angle) * (vPos[2][0] - vPos[1][0]) * ((i&1) ? f : 1.0f); - float y = vPos[1][1] + sin(angle) * (vPos[2][1] - vPos[1][1]) * ((i&1) ? f : 1.0f); - for(j = 0; j < 3; ++j) + float angle = (M_PI * i) / n; // 0 to 2pi + float x = vPos[1][0] + (vPos[2][0] - vPos[1][0]) * cos(angle) * ((i&1) ? f : 1.0f); + float y = vPos[1][1] + (vPos[2][1] - vPos[1][1]) * sin(angle) * ((i&1) ? f : 1.0f); + for(j = 0; j < height; ++j) { - float z = vPos[j][2]; + float z = vPos[0][2] + (vPos[2][2] - vPos[0][2]) * (j / (float)(height - 1)); PatchControl *v; - v = &m_ctrl.data()[j*(2*n+1)+i]; + v = &m_ctrl.data()[j*width+i]; + v->m_vertex[0] = x; + v->m_vertex[1] = y; + v->m_vertex[2] = z; + } + } + } + else if (eType == eXactCone) + { + int n = (width - 1) / 2; // n = number of segments + setDims(width, height); + + // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); + // vPos[1] = aabb.origin; + // vPos[2] = vector3_added(aabb.origin, aabb.extents); + + int i, j; + float f = 1 / cos(M_PI / n); + for(i = 0; i < width; ++i) + { + float angle = (M_PI * i) / n; + for(j = 0; j < height; ++j) + { + float x = vPos[1][0] + (1.0f - (j / (float)(height - 1))) * (vPos[2][0] - vPos[1][0]) * cos(angle) * ((i&1) ? f : 1.0f); + float y = vPos[1][1] + (1.0f - (j / (float)(height - 1))) * (vPos[2][1] - vPos[1][1]) * sin(angle) * ((i&1) ? f : 1.0f); + float z = vPos[0][2] + (vPos[2][2] - vPos[0][2]) * (j / (float)(height - 1)); + PatchControl *v; + v = &m_ctrl.data()[j*width+i]; + v->m_vertex[0] = x; + v->m_vertex[1] = y; + v->m_vertex[2] = z; + } + } + } + else if (eType == eXactSphere) + { + int n = (width - 1) / 2; // n = number of segments (yaw) + int m = (height - 1) / 2; // m = number of segments (pitch) + setDims(width, height); + + // vPos[0] = vector3_subtracted(aabb.origin, aabb.extents); + // vPos[1] = aabb.origin; + // vPos[2] = vector3_added(aabb.origin, aabb.extents); + + int i, j; + float f = 1 / cos(M_PI / n); + float g = 1 / cos(M_PI / (2*m)); + for(i = 0; i < width; ++i) + { + float angle = (M_PI * i) / n; + for(j = 0; j < height; ++j) + { + float angle2 = (M_PI * j) / (2*m); + float x = vPos[1][0] + (vPos[2][0] - vPos[1][0]) * sin(angle2) * ((j&1) ? g : 1.0f) * cos(angle) * ((i&1) ? f : 1.0f); + float y = vPos[1][1] + (vPos[2][1] - vPos[1][1]) * sin(angle2) * ((j&1) ? g : 1.0f) * sin(angle) * ((i&1) ? f : 1.0f); + float z = vPos[1][2] + (vPos[2][2] - vPos[1][2]) * -cos(angle2) * ((j&1) ? g : 1.0f); + PatchControl *v; + v = &m_ctrl.data()[j*width+i]; v->m_vertex[0] = x; v->m_vertex[1] = y; v->m_vertex[2] = z; diff --git a/radiant/patch.h b/radiant/patch.h index 61ecba9b..403c43bc 100644 --- a/radiant/patch.h +++ b/radiant/patch.h @@ -103,6 +103,8 @@ enum EPatchPrefab eCone, eSphere, eXactCylinder, + eXactSphere, + eXactCone, }; enum EMatrixMajor diff --git a/radiant/patchmanip.cpp b/radiant/patchmanip.cpp index 46818cf0..6829fee7 100644 --- a/radiant/patchmanip.cpp +++ b/radiant/patchmanip.cpp @@ -432,11 +432,27 @@ AABB PatchCreator_getBounds() return AABB(Vector3(0, 0, 0), Vector3(64, 64, 64)); } +void DoNewPatchDlg(EPatchPrefab prefab, int minrows, int mincols, int defrows, int defcols, int maxrows, int maxcols); + void Patch_XactCylinder() { UndoableCommand undo("patchCreateXactCylinder"); - Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eXactCylinder, GlobalXYWnd_getCurrentViewType()); + DoNewPatchDlg(eXactCylinder, 3, 7, 3, 13, 0, 0); +} + +void Patch_XactSphere() +{ + UndoableCommand undo("patchCreateXactSphere"); + + DoNewPatchDlg(eXactSphere, 5, 7, 7, 13, 0, 0); +} + +void Patch_XactCone() +{ + UndoableCommand undo("patchCreateXactCone"); + + DoNewPatchDlg(eXactCone, 3, 7, 3, 13, 0, 0); } void Patch_Cylinder() @@ -503,13 +519,11 @@ void Patch_Cone() Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), eCone, GlobalXYWnd_getCurrentViewType()); } -void DoNewPatchDlg(); - void Patch_Plane() { UndoableCommand undo("patchCreatePlane"); - DoNewPatchDlg(); + DoNewPatchDlg(ePlane, 3, 3, 3, 3, 0, 0); } void Patch_InsertInsertColumn() @@ -750,10 +764,12 @@ void Patch_registerCommands() GlobalCommands_insert("DecPatchRow", FreeCaller(), Accelerator(GDK_KP_Subtract, (GdkModifierType)GDK_CONTROL_MASK)); GlobalCommands_insert("NaturalizePatch", FreeCaller(), Accelerator('N', (GdkModifierType)GDK_CONTROL_MASK)); GlobalCommands_insert("PatchCylinder", FreeCaller()); - GlobalCommands_insert("PatchXactCylinder", FreeCaller()); GlobalCommands_insert("PatchDenseCylinder", FreeCaller()); GlobalCommands_insert("PatchVeryDenseCylinder", FreeCaller()); GlobalCommands_insert("PatchSquareCylinder", FreeCaller()); + GlobalCommands_insert("PatchXactCylinder", FreeCaller()); + GlobalCommands_insert("PatchXactSphere", FreeCaller()); + GlobalCommands_insert("PatchXactCone", FreeCaller()); GlobalCommands_insert("PatchEndCap", FreeCaller()); GlobalCommands_insert("PatchBevel", FreeCaller()); GlobalCommands_insert("PatchSquareBevel", FreeCaller()); @@ -796,7 +812,7 @@ void Patch_constructMenu(GtkMenu* menu) create_menu_item_with_mnemonic(menu_in_menu, "Dense Cylinder", "PatchDenseCylinder"); create_menu_item_with_mnemonic(menu_in_menu, "Very Dense Cylinder", "PatchVeryDenseCylinder"); create_menu_item_with_mnemonic(menu_in_menu, "Square Cylinder", "PatchSquareCylinder"); - create_menu_item_with_mnemonic(menu_in_menu, "Exact Cylinder", "PatchXactCylinder"); + create_menu_item_with_mnemonic(menu_in_menu, "Exact Cylinder...", "PatchXactCylinder"); } menu_separator (menu); create_menu_item_with_mnemonic(menu, "End cap", "PatchEndCap"); @@ -810,7 +826,10 @@ void Patch_constructMenu(GtkMenu* menu) } menu_separator (menu); create_menu_item_with_mnemonic(menu, "Cone", "PatchCone"); + create_menu_item_with_mnemonic(menu, "Exact Cone...", "PatchXactCone"); + menu_separator (menu); create_menu_item_with_mnemonic(menu, "Sphere", "PatchSphere"); + create_menu_item_with_mnemonic(menu, "Exact Sphere...", "PatchXactSphere"); menu_separator (menu); create_menu_item_with_mnemonic(menu, "Simple Patch Mesh...", "SimplePatchMesh"); menu_separator (menu); @@ -875,7 +894,7 @@ void Patch_constructMenu(GtkMenu* menu) #include "gtkutil/dialog.h" #include "gtkutil/widget.h" -void DoNewPatchDlg() +void DoNewPatchDlg(EPatchPrefab prefab, int minrows, int mincols, int defrows, int defcols, int maxrows, int maxcols) { ModalDialog dialog; GtkComboBox* width; @@ -911,21 +930,23 @@ void DoNewPatchDlg() { GtkComboBox* combo = GTK_COMBO_BOX(gtk_combo_box_new_text()); - gtk_combo_box_append_text(combo, "3"); - gtk_combo_box_append_text(combo, "5"); - gtk_combo_box_append_text(combo, "7"); - gtk_combo_box_append_text(combo, "9"); - gtk_combo_box_append_text(combo, "11"); - gtk_combo_box_append_text(combo, "13"); - gtk_combo_box_append_text(combo, "15"); - gtk_combo_box_append_text(combo, "17"); - gtk_combo_box_append_text(combo, "19"); - gtk_combo_box_append_text(combo, "21"); - gtk_combo_box_append_text(combo, "23"); - gtk_combo_box_append_text(combo, "25"); - gtk_combo_box_append_text(combo, "27"); - gtk_combo_box_append_text(combo, "29"); - gtk_combo_box_append_text(combo, "31"); // MAX_PATCH_SIZE is 32, so we should be able to do 31... +#define D_ITEM(x) if(x >= mincols && (!maxcols || x <= maxcols)) gtk_combo_box_append_text(combo, #x) + D_ITEM(3); + D_ITEM(5); + D_ITEM(7); + D_ITEM(9); + D_ITEM(11); + D_ITEM(13); + D_ITEM(15); + D_ITEM(17); + D_ITEM(19); + D_ITEM(21); + D_ITEM(23); + D_ITEM(25); + D_ITEM(27); + D_ITEM(29); + D_ITEM(31); // MAX_PATCH_SIZE is 32, so we should be able to do 31... +#undef D_ITEM gtk_widget_show(GTK_WIDGET(combo)); gtk_table_attach(table, GTK_WIDGET(combo), 1, 2, 0, 1, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), @@ -935,21 +956,23 @@ void DoNewPatchDlg() } { GtkComboBox* combo = GTK_COMBO_BOX(gtk_combo_box_new_text()); - gtk_combo_box_append_text(combo, "3"); - gtk_combo_box_append_text(combo, "5"); - gtk_combo_box_append_text(combo, "7"); - gtk_combo_box_append_text(combo, "9"); - gtk_combo_box_append_text(combo, "11"); - gtk_combo_box_append_text(combo, "13"); - gtk_combo_box_append_text(combo, "15"); - gtk_combo_box_append_text(combo, "17"); - gtk_combo_box_append_text(combo, "19"); - gtk_combo_box_append_text(combo, "21"); - gtk_combo_box_append_text(combo, "23"); - gtk_combo_box_append_text(combo, "25"); - gtk_combo_box_append_text(combo, "27"); - gtk_combo_box_append_text(combo, "29"); - gtk_combo_box_append_text(combo, "31"); // MAX_PATCH_SIZE is 32, so we should be able to do 31... +#define D_ITEM(x) if(x >= minrows && (!maxrows || x <= maxrows)) gtk_combo_box_append_text(combo, #x) + D_ITEM(3); + D_ITEM(5); + D_ITEM(7); + D_ITEM(9); + D_ITEM(11); + D_ITEM(13); + D_ITEM(15); + D_ITEM(17); + D_ITEM(19); + D_ITEM(21); + D_ITEM(23); + D_ITEM(25); + D_ITEM(27); + D_ITEM(29); + D_ITEM(31); // MAX_PATCH_SIZE is 32, so we should be able to do 31... +#undef D_ITEM gtk_widget_show(GTK_WIDGET(combo)); gtk_table_attach(table, GTK_WIDGET(combo), 1, 2, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), @@ -978,15 +1001,15 @@ void DoNewPatchDlg() } // Initialize dialog - gtk_combo_box_set_active(width, 0); - gtk_combo_box_set_active(height, 0); + gtk_combo_box_set_active(width, (defcols - mincols) / 2); + gtk_combo_box_set_active(height, (defrows - minrows) / 2); if(modal_dialog_show(window, dialog) == eIDOK) { - int w = gtk_combo_box_get_active(width) * 2 + 3; - int h = gtk_combo_box_get_active(height) * 2 + 3; + int w = gtk_combo_box_get_active(width) * 2 + mincols; + int h = gtk_combo_box_get_active(height) * 2 + minrows; - Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), ePlane, GlobalXYWnd_getCurrentViewType(), w, h); + Scene_PatchConstructPrefab(GlobalSceneGraph(), PatchCreator_getBounds(), TextureBrowser_GetSelectedShader(GlobalTextureBrowser()), prefab, GlobalXYWnd_getCurrentViewType(), w, h); } gtk_widget_destroy(GTK_WIDGET(window));