--*********************************************************** --** THE INDIE STONE ** --*********************************************************** require('Vehicles/ISUI/ISUI3DScene') local FONT_HGT_SMALL = getTextManager():getFontHeight(UIFont.Small) local FONT_HGT_MEDIUM = getTextManager():getFontHeight(UIFont.Medium) EditVehicleUI = ISPanel:derive("EditVehicleUI") EditVehicleUI_Scene = ISUI3DScene:derive("EditVehicleUI_Scene") EditVehicleUI_SwitchView = ISUI3DScene:derive("EditVehicleUI_SwitchView") local Scene = EditVehicleUI_Scene local SwitchView = EditVehicleUI_SwitchView function SwitchView:prerender() if self:isMouseOver() or (self:getView() == self.editor.scene:getView()) then self.borderColor.r = 0.8 self.borderColor.g = 0.8 self.borderColor.b = 0.8 else self.borderColor.r = 0.4 self.borderColor.g = 0.4 self.borderColor.b = 0.4 end ISUI3DScene.prerender(self) end function SwitchView:onMouseDown(x, y) self.editor.prevView = self:getView() self.editor.scene:setView(self:getView()) end function SwitchView:onMouseMove(dx, dy) if self.editor.mouseOverView ~= self then if self.editor.mouseOverView then self.editor.mouseOverView:onMouseMoveOutside(-1, -1) end self.editor.mouseOverView = self self.editor.prevView = self.editor.scene:getView() self.editor.scene:setView(self:getView()) end end function SwitchView:onMouseMoveOutside(dx, dy) if self.editor.mouseOverView == self then self.editor.mouseOverView = nil self.editor.scene:setView(self.editor.prevView) self.editor.prevView = nil end end function SwitchView:onMouseWheel(del) return true end function SwitchView:new(editor, x, y, width, height) local o = ISUI3DScene.new(self, x, y, width, height) o.editor = editor return o end ----- local function vectorComponentToString(n, scale) return tostring(round(n * scale, 3)) end local function vectorToString(v, scale) return vectorComponentToString(v:x(), scale) .. " " .. vectorComponentToString(v:y(), scale) .. " " .. vectorComponentToString(v:z(), scale) end local function drawScalar(ui, label, x, y, v) ui:drawText(label, x, y, 1, 1, 1, 1, UIFont.Small) x = x + getTextManager():MeasureStringX(UIFont.Small, label) local dx = getTextManager():MeasureStringX(UIFont.Small, "99.9999") str = vectorComponentToString(v, 1) ui:drawText(str, x, y, 1, 0, 0, 1, UIFont.Small) end local function drawVector(ui, label, x, y, vx, vy, vz) ui:drawText(label, x, y, 1, 1, 1, 1, UIFont.Small) x = x + getTextManager():MeasureStringX(UIFont.Small, label) local dx = getTextManager():MeasureStringX(UIFont.Small, "99.9999") str = vectorComponentToString(vx, 1) ui:drawText(str, x, y, 1, 0, 0, 1, UIFont.Small) x = x + dx str = vectorComponentToString(vy, 1) ui:drawText(str, x, y, 0, 1, 0, 1, UIFont.Small) x = x + dx str = vectorComponentToString(vz, 1) ui:drawText(str, x, y, 0, 0.5, 1, 1, UIFont.Small) end local function drawArea(ui, label, x, y, area) ui:drawText(label, x, y, 1, 1, 1, 1, UIFont.Small) x = x + getTextManager():MeasureStringX(UIFont.Small, label) local dx = getTextManager():MeasureStringX(UIFont.Small, "99.9999") str = vectorComponentToString(area:getX(), 1) ui:drawText(str, x, y, 1, 0, 0, 1, UIFont.Small) x = x + dx str = vectorComponentToString(area:getY(), 1) ui:drawText(str, x, y, 0, 0.5, 1, 1, UIFont.Small) x = x + dx str = vectorComponentToString(area:getW(), 1) ui:drawText(str, x, y, 1, 1, 1, 1, UIFont.Small) x = x + dx str = vectorComponentToString(area:getH(), 1) ui:drawText(str, x, y, 1, 1, 1, 1, UIFont.Small) end local function alignVectorToGrid(v) local vx = math.floor(v:x() * 100 + 0.5) / 100 local vy = math.floor(v:y() * 100 + 0.5) / 100 local vz = math.floor(v:z() * 100 + 0.5) / 100 v:setComponent(0, vx) v:setComponent(1, vy) v:setComponent(2, vz) return v end ----- EditVehicleUI_ListBox = ISScrollingListBox:derive("EditVehicleUI_ListBox") local ListBox = EditVehicleUI_ListBox function ListBox:prerender() ISScrollingListBox.prerender(self) if self:isMouseOver() and isKeyPressed(Keyboard.KEY_A) then if self:getSelectedCount() == #self.items then self:clearSelection() elseif self.selectionMode == "multi" then for _,item in ipairs(self.items) do item.selected = true end end end end function ListBox:onMouseDown(x, y) if #self.items == 0 then return end local row = self:rowAt(x, y) if row == -1 then self:clearSelection() return end if self.selectionMode == "single" or not isShiftKeyDown() then self:clearSelection() end self.items[row].selected = not self.items[row].selected end function ListBox:clearSelection() for _,item in ipairs(self.items) do item.selected = false end end function ListBox:setSelectedRow(row) self:clearSelection() if self.items[row] then self.items[row].selected = true end end function ListBox:setSelectedRows(rows) self:clearSelection() for _,row in ipairs(rows) do local item = self.items[row] if item then item.selected = true end end end function ListBox:getSelectedItems() local selected = {} for _,item in ipairs(self.items) do if item.selected then table.insert(selected, item) end end return selected end function ListBox:getSelectedCount() local selected = 0 for _,item in ipairs(self.items) do if item.selected then selected = selected + 1 end end return selected end function ListBox:iteratorSelected() return ipairs(self:getSelectedItems()) end function ListBox:indexOf(text) for i,item in ipairs(self.items) do if item.text == text then return i end end return -1 end function ListBox:new(x, y, width, height) local o = ISScrollingListBox.new(self, x, y, width, height) o.selectionMode = "multi" return o end ----- EditVehicleUI_EditPanel = ISPanel:derive("EditVehicleUI_EditPanel") local EditPanel = EditVehicleUI_EditPanel EditVehicleUI_EditArea = EditPanel:derive("EditVehicleUI_EditArea") EditVehicleUI_EditAttachment = EditPanel:derive("EditVehicleUI_EditAttachment") EditVehicleUI_EditChassis = EditPanel:derive("EditVehicleUI_EditChassis") EditVehicleUI_EditPassenger = EditPanel:derive("EditVehicleUI_EditPassenger") EditVehicleUI_EditPhysics = EditPanel:derive("EditVehicleUI_EditPhysics") EditVehicleUI_EditWheel = EditPanel:derive("EditVehicleUI_EditWheel") local EditArea = EditVehicleUI_EditArea local EditAttachment = EditVehicleUI_EditAttachment local EditChassis = EditVehicleUI_EditChassis local EditPassenger = EditVehicleUI_EditPassenger local EditPhysics = EditVehicleUI_EditPhysics local EditWheel = EditVehicleUI_EditWheel function EditPanel:updateEditor() end function EditPanel:prerenderEditor() end function EditPanel:toUI() self.script = self:java1("getVehicleScript", "vehicle") end function EditPanel:onGizmoStart() end function EditPanel:onGizmoChanged(delta) end function EditPanel:onGizmoAccept() end function EditPanel:onGizmoCancel() end function EditPanel:isScaleVehicle() -- return self.parent.scene.javaObject:fromLua0("isScaleVehicle") return true end function EditPanel:createList(x, y, w, h) local list = ListBox:new(x or 0, y or 0, w or self.width, h or self.height) self:addChild(list) return list end function EditPanel:java0(func) return self.parent.scene.javaObject:fromLua0(func) end function EditPanel:java1(func, arg0) return self.parent.scene.javaObject:fromLua1(func, arg0) end function EditPanel:java2(func, arg0, arg1) return self.parent.scene.javaObject:fromLua2(func, arg0, arg1) end function EditPanel:java3(func, arg0, arg1, arg2) return self.parent.scene.javaObject:fromLua3(func, arg0, arg1, arg2) end function EditPanel:java4(func, arg0, arg1, arg2, arg3) return self.parent.scene.javaObject:fromLua4(func, arg0, arg1, arg2, arg3) end function EditPanel:java6(func, arg0, arg1, arg2, arg3, arg4, arg5) return self.parent.scene.javaObject:fromLua6(func, arg0, arg1, arg2, arg3, arg4, arg5) end function EditPanel:java9(func, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) return self.parent.scene.javaObject:fromLua9(func, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) end function EditPanel:new(x, y, width, height) local o = ISPanel.new(self, x, y, width, height) return o end ----- function EditArea:createChildren() local buttonPadY = 4 local buttonHgt = FONT_HGT_MEDIUM + 8 self.list = self:createList(0, 0, self.width, self.height - buttonHgt * 2 - buttonPadY * 3) self.list.doDrawItem = self.doDrawItem self.gizmo = "translate" local button = ISButton:new(10, self.list:getBottom() + buttonPadY, self.width - 40, buttonHgt, "TRANSLATE", self, self.onToggleGizmo) self:addChild(button) self.button = button button = ISButton:new(10, button:getBottom() + buttonPadY, self.width - 40, buttonHgt, "ALIGN TO EXTENTS", self, self.onAlignToExtents) self:addChild(button) self.buttonAlign = button end function EditArea:onToggleGizmo() if self.gizmo == "translate" then self.gizmo = "scale" self.button.title = "SCALE" else self.gizmo = "translate" self.button.title = "TRANSLATE" end end function EditArea:onAlignToExtents() local extents = self.script:getExtents() for _,area in ipairs(self:getSelectedAreas()) do if area:getX() > extents:x() / 2 then area:setX(extents:x() / 2 + area:getW() / 2) elseif area:getX() < -extents:x() / 2 then area:setX(-extents:x() / 2 - area:getW() / 2) elseif area:getY() > extents:z() / 2 then area:setY(extents:z() / 2 + area:getH() / 2) elseif area:getY() < -extents:z() / 2 then area:setY(-extents:z() / 2 - area:getH() / 2) end end end function EditArea:doDrawItem(y, item, alt) local area = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(area:getId(), x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL local scale = self.parent:isScaleVehicle() and 1 or (1 / self.parent.script:getModelScale()) drawArea(self, "", x + indent, y, area) y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditArea:toUI() EditPanel.toUI(self) self.list:clear() for i=1,self.script:getAreaCount() do local area = self.script:getArea(i-1) self.list:addItem(area:getId(), area) end end function EditArea:prerenderEditor() self.list.doDrawItem = self.doDrawItem local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = 1 / script:getModelScale() end local mouseOver = self.list.items[self.list.mouseoverselected] local item = mouseOver or self.list:getSelectedItems()[1] if item then local area = item.item local ox = area:getX() * scale local oy = 0 * scale local oz = area:getY() * scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", self.gizmo) self:java2("setGizmoOrigin", "centerOfMass", "vehicle") -- "ground" end local ext = script:getExtents() local com = script:getCenterOfMassOffset() self:java6("addAABB", com:x(), com:y(), com:z(), ext:x() * scale, ext:y() * scale, ext:z() * scale) for i=1,script:getAreaCount() do local area = script:getArea(i-1) self:java6("addAABB", area:getX() * scale, 0, area:getY() * scale, area:getW() * scale, 0.1, area:getH() * scale, 0.5, 0.5, 0.5) end if mouseOver then local area = mouseOver.item self:java9("addAABB", area:getX() * scale, 0, area:getY() * scale, area:getW() * scale, 0.1, area:getH() * scale, 0, 1, 0) self:java3("addAxis", area:getX() * scale, 0 * scale, area:getY() * scale) else for _,item in self.list:iteratorSelected() do local area = item.item self:java9("addAABB", area:getX() * scale, 0, area:getY() * scale, area:getW() * scale, 0.1, area:getH() * scale, 0, 1, 0) self:java3("addAxis", area:getX() * scale, 0 * scale, area:getY() * scale) end end self.buttonAlign:setEnable(self.list:getSelectedCount() > 0) end function EditArea:getSelectedAreas() local selected = {} for _,item in self.list:iteratorSelected() do table.insert(selected, item.item) end return selected end local function alignAreaToGrid(area) local vx = math.floor(area:getX() * 100 + 0.5) local vy = math.floor(area:getY() * 100 + 0.5) local vw = math.floor(area:getW() * 100 + 0.5) local vh = math.floor(area:getH() * 100 + 0.5) if vw % 2 > 0.001 then vw = vw + 1 end if vh % 2 > 0.001 then vh = vh + 1 end area:setX(vx / 100) area:setY(vy / 100) area:setW(vw / 100) area:setH(vh / 100) end local function alignXYWHToGrid(xywh) local vx = math.floor(xywh.x * 100 + 0.5) local vy = math.floor(xywh.y * 100 + 0.5) local vw = math.floor(xywh.w * 100 + 0.5) local vh = math.floor(xywh.h * 100 + 0.5) if vw % 2 > 0.001 then vw = vw + 1 end if vh % 2 > 0.001 then vh = vh + 1 end xywh.x = vx / 100 xywh.y = vy / 100 xywh.w = vw / 100 xywh.h = vh / 100 end function EditArea:onGizmoStart() self.originalXYWH = {} for _,area in ipairs(self:getSelectedAreas()) do local xywh = { x = area:getX(), y = area:getY(), w = area:getW(), h = area:getH() } if not self:isScaleVehicle() then xywh.x = xywh.x / self.script:getModelScale() xywh.y = xywh.y / self.script:getModelScale() xywh.w = xywh.w / self.script:getModelScale() xywh.h = xywh.h / self.script:getModelScale() end alignXYWHToGrid(xywh) self.originalXYWH[area] = xywh end end function EditArea:onGizmoChanged(delta) if self.parent.scene.gizmoAxis == "None" then return end local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = script:getModelScale() end for _,area in ipairs(self:getSelectedAreas()) do local xywh = self.originalXYWH[area] if self.gizmo == "scale" then area:setW((xywh.w + delta:x() * 2) * scale) area:setH((xywh.h + delta:z() * 2) * scale) end if self.gizmo == "translate" then area:setX((xywh.x + delta:x()) * scale) area:setY((xywh.y + delta:z()) * scale) area:setW(xywh.w * scale) area:setH(xywh.h * scale) end end end function EditArea:onGizmoCancel() local scale = 1 if not self:isScaleVehicle() then scale = self.script:getModelScale() end for _,area in ipairs(self:getSelectedAreas()) do local xywh = self.originalXYWH[area] area:setX(xywh.x * scale) area:setY(xywh.y * scale) area:setW(xywh.w * scale) area:setH(xywh.h * scale) end end function EditArea:new(x, y, width, height) local o = EditPanel.new(self, x, y, width, height) return o end ----- function EditAttachment:createChildren() local buttonPadY = 4 local buttonHgt = FONT_HGT_MEDIUM + 8 local itemHeight = FONT_HGT_SMALL + 2 self.list = self:createList(0, 0, self.width, itemHeight * 6) self.list.doDrawItem = self.doDrawItem self.belowList = ISPanel:new(0, self.list:getBottom() + buttonPadY, self.width, 100) self.belowList:noBackground() self:addChild(self.belowList); self.nameEntry = ISTextEntryBox:new("", 10, 0, self.width - 10 * 2, buttonHgt) self.nameEntry.font = UIFont.Medium self.nameEntry.onCommandEntered = function(self) self.parent.parent:onNameEntered() end self.belowList:addChild(self.nameEntry) local button1 = ISButton:new(10, self.nameEntry:getBottom() + buttonPadY, (self.width - 10 * 3) / 2, buttonHgt, "NEW", self, self.onNewAttachment) self.belowList:addChild(button1) -- button1:setEnable(false) self.buttonNewAttachment = button1 local button2 = ISButton:new(button1:getRight() + 10, button1:getY(), button1.width, buttonHgt, "DELETE", self, self.onDeleteAttachment) button2:setEnable(false) self.belowList:addChild(button2) self.buttonDeleteAttachment = button2 self.gizmo = "translate" local button3 = ISButton:new(10, button2:getBottom() + buttonPadY, self.width - 20, buttonHgt, "TRANSLATE", self, self.onToggleGizmo) self.belowList:addChild(button3) self.button3 = button3 self.transformMode = "Global" local button4 = ISButton:new(10, button3:getBottom() + buttonPadY, self.width - 20, buttonHgt, "GLOBAL", self, self.onToggleGlobalLocal) self.belowList:addChild(button4) self.button4 = button4 self.belowList:setHeight(self.button4:getBottom()) self:setHeight(self.belowList:getBottom()) end function EditAttachment:doDrawItem(y, item, alt) local attach = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end local id = attach:getId() if attach:getBone() then id = id .. " (" .. attach:getBone() .. ")" end self:drawText(id, x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL local offset = attach:getOffset() drawVector(self, "offset: ", x + indent, y, offset:x(), offset:y(), offset:z()) y = y + FONT_HGT_SMALL local rotate = attach:getRotate() drawVector(self, "rotate: ", x + indent, y, rotate:x(), rotate:y(), rotate:z()) y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditAttachment:toUI() EditPanel.toUI(self) local attachIds = {} for _,item in self.list:iteratorSelected() do attachIds[item.item:getId()] = true end self.list:clear() self.list:setScrollHeight(0) for i=1,self.script:getAttachmentCount() do local attach = self.script:getAttachment(i-1) self.list:addItem(attach:getId(), attach) if attachIds[attach:getId()] then self.list.items[i].selected = true end end self.list:sort() end function EditAttachment:prerenderEditor() self.list.doDrawItem = self.doDrawItem local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = 1 / script:getModelScale() end local mouseOver = self.list.items[self.list.mouseoverselected] local item = mouseOver or self.list:getSelectedItems()[1] if not item then self:setSelectedAttachment(nil) return end local attach = mouseOver and mouseOver.item or self:getSelectedAttachments()[1] self:setSelectedAttachment(attach) if attach then self:java3("setGizmoXYZ", attach:getOffset():x() * scale, attach:getOffset():y() * scale, attach:getOffset():z() * scale) self:java1("setGizmoRotate", attach:getRotate()) self:java2("setGizmoOrigin", "vehicleModel", "vehicle") --[[ local parentAttachName = self:java1("getObjectParentAttachment", modelScript:getFullType()) if parentAttachName then local parentName = self:java1("getObjectParent", modelScript:getFullType()) self:java4("setGizmoOrigin", "attachment", modelScript:getFullType(), parentName, parentAttachName) self:java1("setSelectedAttachment", attach:getId()) end --]] self:java6("addAxis", attach:getOffset():x(), attach:getOffset():y(), attach:getOffset():z(), attach:getRotate():x(), attach:getRotate():y(), attach:getRotate():z()) self:java1("setGizmoVisible", self.gizmo) self:java1("setTransformMode", self.transformMode) end end function EditAttachment:doLayout() local top = self:getY() local labelTop = self.parent:getHeight() - self.parent.bottomPanel:getHeight() - 30 local bottom = labelTop - 20 - self.belowList.height - 4 self.list:setHeight(bottom - top) self.belowList:setY(self.list:getBottom() + 4) self:setHeight(self.belowList:getBottom()) end function EditAttachment:onNameEntered() local attach = self:getSelectedAttachments()[1] if not attach then return end local text = self.nameEntry:getInternalText():trim() if text == "" then self.nameEntry:setText(attach:getId()) return end local attach2 = self.script:getAttachmentById(text) if attach2 then self.nameEntry:setText(attach:getId()) return end attach:setId(text) end function EditAttachment:getUniqueAttachmentId(modelScript) for i=1,100 do local id = "attachment"..tostring(i) if not self.script:getAttachmentById(id) then return id end end error "too many attachments" end function EditAttachment:onNewAttachment(button, x, y) local id = self:getUniqueAttachmentId() local attach = ModelAttachment.new(id) self.script:addAttachment(attach) self:toUI() local index = self.list:indexOf(id) self.list.items[index].selected = true self.list:ensureVisible(index) end function EditAttachment:onDeleteAttachment(button, x, y) for _,item in self.list:iteratorSelected() do self.script:removeAttachment(item.item) end self:toUI() end function EditAttachment:onToggleGizmo() if self.gizmo == "translate" then self.gizmo = "rotate" self.button3.title = "ROTATE" else self.gizmo = "translate" self.button3.title = "TRANSLATE" end end function EditAttachment:onToggleGlobalLocal() if self.transformMode == "Global" then self.transformMode = "Local" self.button4.title = "LOCAL" else self.transformMode = "Global" self.button4.title = "GLOBAL" end end function EditAttachment:setSelectedAttachment(attach) if self.selectedAttachment == attach then return end self.selectedAttachment = attach self.buttonDeleteAttachment:setEnable(attach ~= nil) if not attach then self.nameEntry:clear() return end self.nameEntry:setText(attach:getId()) end function EditAttachment:getSelectedAttachments() local selected = {} for _,item2 in self.list:iteratorSelected() do local attach = self.script:getAttachmentById(item2.item:getId()) if attach then table.insert(selected, attach) end end return selected end function EditAttachment:getSelectedAttachmentIds() local selected = {} for _,item2 in self.list:iteratorSelected() do table.insert(selected, item2.item:getId()) end return selected end function EditAttachment:onGizmoStart() self.originalOffset = {} self.originalRotate = {} for _,attach in ipairs(self:getSelectedAttachments()) do if self.gizmo == "translate" then self.originalOffset[attach] = alignVectorToGrid(Vector3f.new(attach:getOffset()), self:java0("getGridMult")) end if self.gizmo == "rotate" then self.originalRotate[attach] = Vector3f.new(attach:getRotate()) end end end function EditAttachment:onGizmoChanged(delta) if self.parent.scene.gizmoAxis == "None" then return end for _,attach in ipairs(self:getSelectedAttachments()) do if self.gizmo == "translate" then attach:getOffset():set(self.originalOffset[attach]):add(delta) end if self.gizmo == "rotate" then self:java2("applyDeltaRotation", attach:getRotate():set(self.originalRotate[attach]), delta) end end end function EditAttachment:onGizmoCancel() for _,attach in ipairs(self:getSelectedAttachments()) do if self.gizmo == "translate" then attach:getOffset():set(self.originalOffset[attach]) end if self.gizmo == "rotate" then attach:getRotate():set(self.originalRotate[attach]) end end end function EditAttachment:new(x, y, width, height) local o = EditPanel.new(self, x, y, width, height) return o end ----- function EditChassis:createChildren() self.list = self:createList(0, 0, self.width, self.height) self.list.doDrawItem = self.doDrawItem self.list.selectionMode = "single" end function EditChassis:toUI() EditPanel.toUI(self) self.list:clear() self.list:addItem("model.scale", "model.scale") self.list:addItem("model.offset", "model.offset") self.list:addItem("centerOfMassOffset", "centerOfMassOffset") self.list:addItem("extents", "extents") self.list:addItem("physicsChassisShape", "physicsChassisShape") self.list:addItem("shadowExtents", "shadowExtents") self.list:addItem("shadowOffset", "shadowOffset") end function EditChassis:doDrawItem(y, item, alt) local which = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(item.text, x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL local scale = self.parent:isScaleVehicle() and 1 or (1 / self.parent.script:getModelScale()) local offset = nil local offset2 = nil if which == "model.offset" then offset = self.parent.script:getModel():getOffset() elseif which == "model.scale" then local modelScale = self.parent.script:getModelScale() drawScalar(self, "", x + indent, y, modelScale) elseif which == "centerOfMassOffset" then offset = self.parent.script:getCenterOfMassOffset() elseif which == "extents" then offset = self.parent.script:getExtents() elseif which == "physicsChassisShape" then offset = self.parent.script:getPhysicsChassisShape() elseif which == "shadowExtents" then offset2 = self.parent.script:getShadowExtents() elseif which == "shadowOffset" then offset2 = self.parent.script:getShadowOffset() end if offset then drawVector(self, "", x + indent, y, offset:x() * scale, offset:y() * scale, offset:z() * scale) end if offset2 then drawVector(self, "", x + indent, y, offset2:x() * scale, 0.0, offset2:y() * scale) end y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditChassis:prerenderEditor() self.list.doDrawItem = self.doDrawItem self:addAABB(self.script:getPhysicsChassisShape(), self.script:getCenterOfMassOffset(), 1, 1, 1) local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] if item then local which = item.item local scale = 1 if not self:isScaleVehicle() then scale = self.script:getModelScale() end if which == "centerOfMassOffset" then local offset = self.script:getCenterOfMassOffset() local ox,oy,oz = offset:x() / scale, offset:y() / scale, offset:z() / scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "translate") self:java2("setGizmoOrigin", "centerOfMass", "vehicle") end if which == "extents" then local offset = self.script:getCenterOfMassOffset() local ox,oy,oz = offset:x() / scale, offset:y() / scale, offset:z() / scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "scale") self:java2("setGizmoOrigin", "centerOfMass", "vehicle") self:addAABB(self.script:getExtents(), self.script:getCenterOfMassOffset(), 0, 1, 0) end if which == "model.offset" then local offset = self.script:getModel():getOffset() local ox,oy,oz = offset:x() / scale, offset:y() / scale, offset:z() / scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "translate") self:java2("setGizmoOrigin", "centerOfMass", "vehicle") end if which == "model.scale" then local offset = self.script:getCenterOfMassOffset() local ox,oy,oz = 0.0, 0.0, 0.0 self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "scale") self:java2("setGizmoOrigin", "centerOfMass", "vehicle") end if which == "physicsChassisShape" then local offset = self.script:getCenterOfMassOffset() local ox,oy,oz = offset:x() / scale, offset:y() / scale, offset:z() / scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "scale") self:java2("setGizmoOrigin", "centerOfMass", "vehicle") self:addAABB(self.script:getPhysicsChassisShape(), self.script:getCenterOfMassOffset(), 0, 1, 0) for i=1,self.script:getPhysicsShapeCount() do local shape = self.script:getPhysicsShape(i-1) if shape:getTypeString() == "box" then self:java6("addBox3D", shape:getOffset(), shape:getExtents(), shape:getRotate(), 0, 1, 0) end if shape:getTypeString() == "sphere" then self:addSphere(shape:getOffset(), shape:getRadius(), 0, 1, 0) end end end if which == "shadowExtents" then local offset = self.script:getShadowOffset() local extents = self.script:getShadowExtents() local ox,oy,oz = offset:x() / scale, 0.0, offset:y() / scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "scale") self:java2("setGizmoOrigin", "none") self.tempVector3f_1:set(offset:x(), 0.0, offset:y()) self.tempVector3f_2:set(extents:x(), 0.2, extents:y()) self:addAABB(self.tempVector3f_2, self.tempVector3f_1, 0, 1, 0) end if which == "shadowOffset" then local offset = self.script:getShadowOffset() local extents = self.script:getShadowExtents() local ox,oy,oz = offset:x() / scale, 0.0, offset:y() / scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "translate") self:java2("setGizmoOrigin", "none") self.tempVector3f_1:set(offset:x(), 0.0, offset:y()) self.tempVector3f_2:set(extents:x(), 0.2, extents:y()) self:addAABB(self.tempVector3f_2, self.tempVector3f_1, 0, 1, 0) end end end function EditChassis:addAABB(box, offset, r, g, b) self:java9("addAABB", offset:x(), offset:y(), offset:z(), box:x(), box:y(), box:z(), r, g, b) end function EditChassis:addSphere(offset, radius, r, g, b) local extents = self.tempSphereExtents or Vector3f.new() extents:setComponent(0, radius * 2) extents:setComponent(1, radius * 2) extents:setComponent(2, radius * 2) self:addAABB(extents, offset, 0, 1, 0) end local function alignExtentsToGrid(v) local vx = math.floor(v:x() * 100 + 0.5) local vy = math.floor(v:y() * 100 + 0.5) local vz = math.floor(v:z() * 100 + 0.5) if vx % 2 > 0.001 then vx = vx + 1 end if vy % 2 > 0.001 then vy = vy + 1 end if vz % 2 > 0.001 then vz = vz + 1 end v:setComponent(0, vx / 100) v:setComponent(1, vy / 100) v:setComponent(2, vz / 100) end function EditChassis:onGizmoStart() local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] if item then local which = item.item if which == "centerOfMassOffset" then self.originalCenterOfMassOffset = Vector3f.new(self.script:getCenterOfMassOffset()) end if which == "extents" then self.originalExtents = Vector3f.new(self.script:getExtents()) end if which == "model.offset" then self.originalModelOffset = Vector3f.new(self.script:getModel():getOffset()) end if which == "model.scale" then self.originalModelScale = self.script:getModelScale() end if which == "physicsChassisShape" then self.originalChassisExtents = Vector3f.new(self.script:getPhysicsChassisShape()) end if which == "shadowExtents" then self.originalShadowExtents = Vector2f.new(self.script:getShadowExtents()) end if which == "shadowOffset" then self.originalShadowOffset = Vector2f.new(self.script:getShadowOffset()) end end end function EditChassis:onGizmoChanged(delta) if self.parent.scene.gizmoAxis == "None" then return end local item = self.list:getSelectedItems()[1] if item then local which = item.item local scale = 1 if not self:isScaleVehicle() then scale = self.script:getModelScale() end local scenePos = self:java0("getGizmoPos") if which == "centerOfMassOffset" then self.script:getCenterOfMassOffset():set(self.originalCenterOfMassOffset):add(delta) end if which == "extents" then local extents = Vector3f.new(delta) extents:mul(2 * scale) extents:add(self.originalExtents) if extents:x() < 0.1 then extents:setComponent(0, 0.1) end if extents:y() < 0.1 then extents:setComponent(1, 0.1) end if extents:z() < 0.1 then extents:setComponent(2, 0.1) end self.script:getExtents():set(extents) end if which == "model.offset" then self.script:getModel():getOffset():set(self.originalModelOffset):add(delta) end if which == "model.scale" then local add = math.max(delta:get(0), math.max(delta:get(1), delta:get(2))) local subtract = math.min(delta:get(0), math.min(delta:get(1), delta:get(2))) self.script:setModelScale(self.originalModelScale + add + subtract) end if which == "physicsChassisShape" then local extents = Vector3f.new(delta) extents:mul(2 * scale) extents:add(self.originalChassisExtents) if extents:x() < 0.1 then extents:setComponent(0, 0.1) end if extents:y() < 0.1 then extents:setComponent(1, 0.1) end if extents:z() < 0.1 then extents:setComponent(2, 0.1) end self.script:getPhysicsChassisShape():set(extents) end if which == "shadowExtents" then self.script:getShadowExtents():set(self.originalShadowExtents):add(delta:x(), delta:z()) end if which == "shadowOffset" then self.script:getShadowOffset():set(self.originalShadowOffset):add(delta:x(), delta:z()) end end end function EditChassis:onGizmoCancel() local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] if item then local which = item.item if which == "centerOfMassOffset" then self.script:getCenterOfMassOffset():set(self.originalCenterOfMassOffset) end if which == "extents" then self.script:getExtents():set(self.originalExtents) end if which == "model.offset" then self.script:getModel():getOffset():set(self.originalModelOffset) end if which == "model.scale" then self.script:setModelScale(self.originalModelScale) end if which == "physicsChassisShape" then self.script:getPhysicsChassisShape():set(self.originalChassisExtents) end if which == "shadowExtents" then self.script:getShadowExtents():set(self.originalShadowExtents) end if which == "shadowOffset" then self.script:getShadowOffset():set(self.originalShadowOffset) end end end function EditChassis:new(x, y, width, height) local o = EditPanel.new(self, x, y, width, height) o.tempVector3f_1 = Vector3f:new() o.tempVector3f_2 = Vector3f:new() return o end ----- function EditPassenger:createChildren() self.list = self:createList(0, 0, self.width, 24 * 6) self.list.doDrawItem = self.doDrawItem self.list2 = self:createList(0, self.list:getBottom() + 10, self.width, 24 * 6) self.list2.doDrawItem = self.doDrawItem2 self.list2.itemheight = FONT_HGT_SMALL * 3 + 2 end function EditPassenger:doDrawItem(y, item, alt) local pngr = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(pngr:getId(), x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditPassenger:doDrawItem2(y, item, alt) local posn = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(posn:getId(), x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL local scale = self.parent:isScaleVehicle() and 1 or (1 / self.parent.script:getModelScale()) local offset = posn:getOffset() drawVector(self, "offset: ", x + indent, y, offset:x() * scale, offset:y() * scale, offset:z() * scale) y = y + FONT_HGT_SMALL local rotate = posn:getRotate() drawVector(self, "rotate: ", x + indent, y, rotate:x() * scale, rotate:y() * scale, rotate:z() * scale) y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditPassenger:prerenderEditor() local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] if item then local pngr = item.item self:setSelectedPassenger(pngr) else self:setSelectedPassenger(nil) end local scale = 1 if not self:isScaleVehicle() then scale = 1 / self.script:getModelScale() end local item = self.list.items[self.list.mouseoverselected] if item and not item.selected then local pngr = item.item for _,id in ipairs(self:getSelectedPositionIds()) do local posn = pngr:getPositionById(id) self:java3("addAxis", posn:getOffset():x() * scale, posn:getOffset():y() * scale, posn:getOffset():z() * scale) end else for _,posn in ipairs(self:getSelectedPositions()) do self:java3("addAxis", posn:getOffset():x() * scale, posn:getOffset():y() * scale, posn:getOffset():z() * scale) end end self:prerenderEditor2() end function EditPassenger:setSelectedPassenger(pngr) if self.selectedPassenger == pngr then return end self.selectedPassenger = pngr if not pngr then self.list2:clear() return end local posnIds = {} for _,item in self.list2:iteratorSelected() do posnIds[item.item:getId()] = true end self.list2:clear() self.list2:setScrollHeight(0) for i=1,pngr:getPositionCount() do local posn = pngr:getPosition(i-1) self.list2:addItem(posn:getId(), posn) if posnIds[posn:getId()] then self.list2.items[i].selected = true end end if self.list2:getSelectedCount() == 0 then self.list2:setSelectedRow(1) end end function EditPassenger:prerenderEditor2() self.list.doDrawItem = self.doDrawItem self.list2.doDrawItem = self.doDrawItem2 local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] local item2 = self.list2.items[self.list2.mouseoverselected] or self.list2:getSelectedItems()[1] if item and item2 then local script = self.script local modelScale = script:getModelScale() local scale = 1 if not self:isScaleVehicle() then scale = 1 / modelScale end local pngr = item.item local posn = item2.item local offset = posn:getOffset() if offset:x() > script:getExtents():x() then offset:setComponent(0, script:getExtents():x()) elseif offset:x() < -script:getExtents():x() then offset:setComponent(0, -script:getExtents():x()) end if offset:y() > script:getExtents():y() then offset:setComponent(1, script:getExtents():y()) elseif offset:y() < -script:getExtents():y() then offset:setComponent(1, -script:getExtents():y()) end if offset:z() > script:getExtents():z() then offset:setComponent(2, script:getExtents():z()) elseif offset:z() < -script:getExtents():z() then offset:setComponent(2, -script:getExtents():z()) end local ox = offset:x() * scale local oy = offset:y() * scale local oz = offset:z() * scale self:java3("setGizmoXYZ", ox, oy, oz) self:java4("setPassengerPosition", "character", "vehicle", pngr:getId(), posn:getId()) self:java2("setObjectVisible", "character", true) self:java1("setGizmoVisible", "translate") self:java2("setGizmoOrigin", "vehicleModel", "vehicle") else self:java2("setObjectVisible", "character", false) end end function EditPassenger:toUI() EditPanel.toUI(self) self.list:clear() for i=1,self.script:getPassengerCount() do local pngr = self.script:getPassenger(i-1) self.list:addItem(pngr:getId(), pngr) end self.list:setSelectedRow(1) end function EditPassenger:getSelectedPositions() local selected = {} for _,item in self.list:iteratorSelected() do local pngr = item.item for _,item2 in self.list2:iteratorSelected() do local posn = pngr:getPositionById(item2.item:getId()) if posn then table.insert(selected, posn) end end end return selected end function EditPassenger:getSelectedPositionIds() local selected = {} for _,item2 in self.list2:iteratorSelected() do table.insert(selected, item2.item:getId()) end return selected end function EditPassenger:onGizmoStart() self.originalOffset = {} for _,posn in ipairs(self:getSelectedPositions()) do self.originalOffset[posn] = alignVectorToGrid(Vector3f.new(posn:getOffset())) if not self:isScaleVehicle() then self.originalOffset[posn]:mul(1 / self.script:getModelScale()) end end end function EditPassenger:onGizmoChanged(delta) if self.parent.scene.gizmoAxis == "None" then return end local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = script:getModelScale() end for _,posn in ipairs(self:getSelectedPositions()) do posn:getOffset():set(self.originalOffset[posn]):add(delta) posn:getOffset():mul(scale) end end function EditPassenger:onGizmoCancel() local scale = 1 if not self:isScaleVehicle() then scale = self.script:getModelScale() end for _,posn in ipairs(self:getSelectedPositions()) do posn:getOffset():set(self.originalOffset[posn]:mul(scale)) end end function EditPassenger:new(x, y, width, height) local o = EditPanel.new(self, x, y, width, height) o:noBackground() return o end ----- function EditPhysics:createChildren() self.list = self:createList(0, 0, self.width, 24 * 6) self.list.selectionMode = "single" self.list.doDrawItem = self.doDrawItem self.list2 = self:createList(0, self.list:getBottom() + 10, self.width, 24 * 6) self.list2.selectionMode = "single" self.list2.doDrawItem = self.doDrawItem2 self.list2.itemheight = FONT_HGT_SMALL * 3 + 2 local buttonPadY = 4 local buttonHgt = FONT_HGT_MEDIUM + 8 self.transformMode = "Global" local button4 = ISButton:new(10, self.list2:getBottom() + buttonPadY, self.width - 20, buttonHgt, "GLOBAL", self, self.onToggleGlobalLocal) self:addChild(button4) self.button4 = button4 end function EditPhysics:onToggleGlobalLocal() if self.transformMode == "Global" then self.transformMode = "Local" self.button4.title = "LOCAL" else self.transformMode = "Global" self.button4.title = "GLOBAL" end end function EditPhysics:doDrawItem(y, item, alt) local shape = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(shape:getTypeString(), x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditPhysics:doDrawItem2(y, item, alt) local shape = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(item.text, x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL local scale = self.parent:isScaleVehicle() and 1 or (1 / self.parent.script:getModelScale()) if item.text == "offset" then local v = shape:getOffset() drawVector(self, " ", x + indent, y, v:x() * scale, v:y() * scale, v:z() * scale) y = y + FONT_HGT_SMALL end if item.text == "extents" then local v = shape:getExtents() drawVector(self, " ", x + indent, y, v:x() * scale, v:y() * scale, v:z() * scale) y = y + FONT_HGT_SMALL end if item.text == "radius" then local radius = shape:getRadius() drawScalar(self, " ", x + indent, y, radius * scale) y = y + FONT_HGT_SMALL end if item.text == "rotate" then local rotate = shape:getRotate() drawVector(self, " ", x + indent, y, rotate:x(), rotate:y(), rotate:z()) y = y + FONT_HGT_SMALL end self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditPhysics:prerenderEditor() local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] if item then local shape = item.item self:setSelectedShape(shape) else self:setSelectedShape(nil) end local scale = 1 if not self:isScaleVehicle() then scale = 1 / self.script:getModelScale() end -- local item = self.list.items[self.list.mouseoverselected] for i=1,self.script:getPhysicsShapeCount() do local shape = self.script:getPhysicsShape(i-1) if item and shape == item.item then elseif shape:getTypeString() == "box" then local offset = shape:getOffset() local extents = shape:getExtents() self:java6("addBox3D", offset, extents, shape:getRotate(), 1.0, 1.0, 1.0) elseif shape:getTypeString() == "sphere" then self:addSphere(shape:getOffset(), shape:getRadius(), 1.0, 1.0, 1.0) end end if item then local shape = item.item local offset = shape:getOffset() self:java3("addAxis", offset:x() * scale, offset:y() * scale, offset:z() * scale) if shape:getTypeString() == "box" then local offset = shape:getOffset() local extents = shape:getExtents() self:java6("addBox3D", offset, extents, shape:getRotate(), 0.0, 1.0, 0.0) end if shape:getTypeString() == "sphere" then self:addSphere(shape:getOffset(), shape:getRadius(), 0.0, 1.0, 0.0) end end self:prerenderEditor2() end function EditPhysics:addAABB(extents, offset, r, g, b) self:java9("addAABB", offset:x(), offset:y(), offset:z(), extents:x(), extents:y(), extents:z(), r, g, b) end function EditPhysics:addSphere(offset, radius, r, g, b) local extents = self.tempSphereExtents or Vector3f.new() extents:setComponent(0, radius * 2) extents:setComponent(1, radius * 2) extents:setComponent(2, radius * 2) self:addAABB(extents, offset, r, g, b) end function EditPhysics:setSelectedShape(shape) if self.selectedShape == shape then return end self.selectedShape = shape if not shape then self.list2:clear() return end local selected = {} for index,item in self.list2:iteratorSelected() do selected[index] = true end self.list2:clear() self.list2:setScrollHeight(0) self.list2:addItem("offset", shape) self.list2.items[1].selected = selected[1] ~= nil if shape:getTypeString() == "box" then self.list2:addItem("extents", shape) self.list2.items[2].selected = selected[2] ~= nil self.list2:addItem("rotate", shape) self.list2.items[3].selected = selected[3] ~= nil end if shape:getTypeString() == "sphere" then self.list2:addItem("radius", shape) self.list2.items[1].selected = selected[1] ~= nil end if self.list2:getSelectedCount() == 0 then self.list2:setSelectedRow(1) end end function EditPhysics:prerenderEditor2() self.list.doDrawItem = self.doDrawItem self.list2.doDrawItem = self.doDrawItem2 local item = self.list.items[self.list.mouseoverselected] or self.list:getSelectedItems()[1] local item2 = self.list2.items[self.list2.mouseoverselected] or self.list2:getSelectedItems()[1] if item and item2 then local script = self.script local modelScale = script:getModelScale() local scale = 1 if not self:isScaleVehicle() then scale = 1 / modelScale end local shape = item.item local offset = shape:getOffset() local ox = offset:x() * scale local oy = offset:y() * scale local oz = offset:z() * scale self:java3("setGizmoXYZ", ox, oy, oz) self:java2("setGizmoOrigin", "none") if shape:getTypeString() == "box" then self:java1("setGizmoRotate", shape:getRotate()) else self:java0("clearGizmoRotate") end self:java1("setTransformMode", self.transformMode) if item2.text == "offset" then self:java1("setGizmoVisible", "translate") end if item2.text == "extents" or item2.text == "radius" then self:java1("setGizmoVisible", "scale") end if item2.text == "rotate" then self:java1("setGizmoVisible", "rotate") end end end function EditPhysics:toUI() EditPanel.toUI(self) self.list:clear() for i=1,self.script:getPhysicsShapeCount() do local shape = self.script:getPhysicsShape(i-1) self.list:addItem(shape:getTypeString(), shape) end self.list:setSelectedRow(1) end function EditPhysics:indexOfShape(shape) for i=1,self.script:getPhysicsShapeCount() do local shape2 = self.script:getPhysicsShape(i-1) if shape == shape2 then return i-1 end end return -1 end function EditPhysics:getSelectedShapes() local selected = {} for _,item in self.list:iteratorSelected() do local index = self:indexOfShape(item.item) if index ~= -1 then table.insert(selected, self.script:getPhysicsShape(index)) end end return selected end local function alignScalarToGrid(s) return math.floor(s * 100 + 0.5) / 100 end function EditPhysics:onGizmoStart() self.originalValue = {} for _,shape in ipairs(self:getSelectedShapes()) do local t = {} t.offset = alignVectorToGrid(Vector3f.new(shape:getOffset())) t.extents = alignVectorToGrid(Vector3f.new(shape:getExtents())) t.rotate = Vector3f.new(shape:getRotate()) t.radius = alignScalarToGrid(shape:getRadius()) if not self:isScaleVehicle() then t.offset:mul(1 / self.script:getModelScale()) t.extents:mul(1 / self.script:getModelScale()) t.radius = t.radius * (1 / self.script:getModelScale()) end self.originalValue[shape] = t end end function EditPhysics:onGizmoChanged(delta) if self.parent.scene.gizmoAxis == "None" then return end local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = script:getModelScale() end local item2 = self.list2:getSelectedItems()[1] if not item2 then return end for _,shape in ipairs(self:getSelectedShapes()) do local val = self.originalValue[shape] if item2.text == "offset" then shape:getOffset():set(val.offset):add(delta) shape:getOffset():mul(scale) end if item2.text == "extents" then local extents = Vector3f.new(delta) extents:mul(2 * scale) extents:add(val.extents) if extents:x() < 0.1 then extents:setComponent(0, 0.1) end if extents:y() < 0.1 then extents:setComponent(1, 0.1) end if extents:z() < 0.1 then extents:setComponent(2, 0.1) end shape:getExtents():set(extents) end if item2.text == "rotate" then self:java2("applyDeltaRotation", shape:getRotate():set(val.rotate), delta) end if item2.text == "radius" then local dxyz = delta:x() if math.abs(delta:y()) > math.abs(dxyz) then dxyz = delta:y() end if math.abs(delta:z()) > math.abs(dxyz) then dxyz = delta:z() end shape:setRadius(val.radius + dxyz * scale) end end end function EditPhysics:onGizmoCancel() local scale = 1 if not self:isScaleVehicle() then scale = self.script:getModelScale() end for _,shape in ipairs(self:getSelectedShapes()) do local val = self.originalValue[shape] shape:getOffset():set(val.offset:mul(scale)) shape:getExtents():set(val.extents:mul(scale)) shape:getRotate():set(val.rotate) shape:setRadius(val.radius) end end function EditPhysics:new(x, y, width, height) local o = EditPanel.new(self, x, y, width, height) o:noBackground() return o end ----- function EditWheel:createChildren() self.list = self:createList() self.list.doDrawItem = self.doDrawItem end function EditWheel:doDrawItem(y, item, alt) local wheel = item.item local x = 4 local indent = 16 local isMouseOver = self.mouseoverselected == item.index and not self:isMouseOverScrollBar() if item.selected then self:drawRect(0, y, self:getWidth(), item.height-1, 0.3, 0.7, 0.35, 0.15) elseif isMouseOver then self:drawRect(1, y + 1, self:getWidth() - 2, item.height - 2, 0.25, 1.0, 1.0, 1.0) end self:drawText(wheel:getId(), x, y, 1, 1, 1, 1, UIFont.Small) y = y + FONT_HGT_SMALL local offset = wheel:getOffset() local scale = self.parent:isScaleVehicle() and 1 or (1 / self.parent.script:getModelScale()) drawVector(self, "offset: ", x + indent, y, offset:x() * scale, offset:y() * scale, offset:z() * scale) y = y + FONT_HGT_SMALL self:drawRect(x, y, self.width - 4 * 2, 2, 1.0, 0.5, 0.5, 0.5) y = y + 2 return y end function EditWheel:toUI() EditPanel.toUI(self) self.list:clear() for i=1,self.script:getWheelCount() do local wheel = self.script:getWheel(i-1) self.list:addItem(wheel:getId(), wheel) end end function EditWheel:prerenderEditor() self.list.doDrawItem = self.doDrawItem local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = 1 / script:getModelScale() end local mouseOver = self.list.items[self.list.mouseoverselected] local item = mouseOver or self.list:getSelectedItems()[1] if item then local wheel = item.item local offset = wheel:getOffset() local ox = offset:x() * scale local oy = offset:y() * scale local oz = offset:z() * scale self:java3("setGizmoXYZ", ox, oy, oz) self:java1("setGizmoVisible", "translate") self:java2("setGizmoOrigin", "vehicleModel", "vehicle") end if mouseOver then local wheel = mouseOver.item self:java3("addAxis", wheel:getOffset():x() * scale, wheel:getOffset():y() * scale, wheel:getOffset():z() * scale) else for _,item in self.list:iteratorSelected() do local wheel = item.item self:java3("addAxis", wheel:getOffset():x() * scale, wheel:getOffset():y() * scale, wheel:getOffset():z() * scale) end end end function EditWheel:getSelectedWheels() local selected = {} for _,item in self.list:iteratorSelected() do table.insert(selected, item.item) end return selected end function EditWheel:onGizmoStart() self.originalOffset = {} for _,wheel in ipairs(self:getSelectedWheels()) do self.originalOffset[wheel] = alignVectorToGrid(Vector3f.new(wheel:getOffset())) if not self:isScaleVehicle() then self.originalOffset[wheel]:mul(1 / self.script:getModelScale()) end end end function EditWheel:onGizmoChanged(delta) if self.parent.scene.gizmoAxis == "None" then return end local script = self.script local scale = 1 if not self:isScaleVehicle() then scale = script:getModelScale() end for _,wheel in ipairs(self:getSelectedWheels()) do wheel:getOffset():set(self.originalOffset[wheel]):add(delta) wheel:getOffset():mul(scale) end end function EditWheel:onGizmoCancel() local scale = 1 if not self:isScaleVehicle() then scale = self.script:getModelScale() end for _,wheel in ipairs(self:getSelectedWheels()) do wheel:getOffset():set(self.originalOffset[wheel]):mul(scale) end end function EditWheel:new(x, y, width, height) local o = EditPanel.new(self, x, y, width, height) return o end ----- function Scene:prerenderEditor() self.javaObject:fromLua1("setGizmoVisible", "none") self.javaObject:fromLua1("setGizmoOrigin", "none") self.javaObject:fromLua1("setTransformMode", "Global") self.javaObject:fromLua0("clearGizmoRotate") self.javaObject:fromLua0("clearAABBs") self.javaObject:fromLua0("clearAxes") self.javaObject:fromLua0("clearBox3Ds") end function Scene:prerender() ISUI3DScene.prerender(self) end function Scene:onMouseDown(x, y) ISUI3DScene.onMouseDown(self, x, y) self.gizmoAxis = self.javaObject:fromLua2("testGizmoAxis", x, y) if self.gizmoAxis ~= "None" then local scenePos = self.javaObject:fromLua0("getGizmoPos") self.gizmoStartScenePos = alignVectorToGrid(Vector3f.new(scenePos)) self.gizmoClickScenePos = alignVectorToGrid(self.javaObject:uiToScene(x, y, 0, Vector3f.new())) self.javaObject:fromLua3("startGizmoTracking", x, y, self.gizmoAxis) self:onGizmoStart() end end function Scene:onMouseMove(dx, dy) if self.gizmoAxis == "None" then ISUI3DScene.onMouseMove(self, dx, dy) else local x,y = self:getMouseX(),self:getMouseY() local newPos = alignVectorToGrid(self.javaObject:uiToScene(x, y, 0, Vector3f.new())) newPos:sub(self.gizmoClickScenePos) newPos:add(self.gizmoStartScenePos) self.javaObject:fromLua2("dragGizmo", x, y) end end function Scene:onMouseUp(x, y) ISUI3DScene.onMouseUp(self, x, y) if self.gizmoAxis ~= "None" then self.gizmoAxis = "None" self.javaObject:fromLua0("stopGizmoTracking") self:onGizmoAccept() end end function Scene:onMouseUpOutside(x, y) self:onMouseUp() end function Scene:onRightMouseDown(x, y) if self.gizmoAxis ~= "None" then self.gizmoAxis = "None" self.javaObject:fromLua0("stopGizmoTracking") self.mouseDown = false self.javaObject:fromLua1("setGizmoPos", self.gizmoStartScenePos) self:onGizmoCancel() end end function Scene:onGizmoStart() self.parent.editUI.current:onGizmoStart() end function Scene:onGizmoChanged(delta) if self.gizmoAxis == "None" then return end -- cancelled via onRightMouseUp self.parent.editUI.current:onGizmoChanged(delta) end function Scene:onGizmoAccept() self.parent.editUI.current:onGizmoAccept() end function Scene:onGizmoCancel() self.parent.editUI.current:onGizmoCancel() end function Scene:new(x, y, width, height) local o = ISUI3DScene.new(self, x, y, width, height) o.gizmoAxis = "None" return o end ----- function EditVehicleUI:createChildren() self.scene = Scene:new(0, 0, self.width, self.height) self.scene:initialise() self.scene:instantiate() self.scene:setAnchorRight(true) self.scene:setAnchorBottom(true) self:addChild(self.scene) self.scene.javaObject:fromLua1("setGizmoScale", 1.0 / 5.0) self.scene.javaObject:fromLua1("setDrawGridAxes", true) self.scene.javaObject:fromLua1("createVehicle", "vehicle") local initialScript = getEditVehicleState():fromLua0("getInitialScript") if initialScript then self.scene.javaObject:fromLua2("setVehicleScript", "vehicle", initialScript) end self.scene.javaObject:fromLua1("createCharacter", "character") self.scene.javaObject:fromLua2("setObjectVisible", "character", false) local viewW = 150 local viewH = 100 self.bottomPanel = ISPanel:new(0, self.height - viewH, self.width, viewH) self.bottomPanel:setAnchorTop(false) self.bottomPanel:setAnchorLeft(false) self.bottomPanel:setAnchorRight(false) self.bottomPanel:setAnchorBottom(true) self.bottomPanel:noBackground() self:addChild(self.bottomPanel) local viewNames = {'Left', 'Right', 'Top', 'Bottom', 'Front', 'Back'} local viewX = (self.width - #viewNames * viewW + (#viewNames - 1) * 10) / 2 local viewY = 0 self.views = {} for _,viewName in ipairs(viewNames) do local view = SwitchView:new(self, viewX, viewY, viewW, viewH) view:initialise() view:instantiate() view:setAnchorTop(false) view:setAnchorRight(false) view:setAnchorBottom(true) view:setView(viewName) view.javaObject:fromLua1("setZoom", 4) view.javaObject:fromLua1("setDrawGrid", false) view.javaObject:fromLua1("createVehicle", "vehicle1") self.bottomPanel:addChild(view) table.insert(self.views, view) viewX = viewX + viewW + 10 end local width = 250 local height = FONT_HGT_MEDIUM + 3 * 2 local combo = ISComboBox:new(self.width / 2 - width / 2, 10, width, height, self, self.onComboVehicle) combo:setEditable(true) combo:initialise() combo:instantiate() combo:setAnchorLeft(false) self:addChild(combo) self.scriptCombo = combo local scripts = getScriptManager():getAllVehicleScripts() local sorted = {} for i=1,scripts:size() do local script = scripts:get(i-1) table.insert(sorted, script:getFullName()) end table.sort(sorted) local scriptNameScene = self.scene.javaObject:fromLua1("getVehicleScript", "vehicle"):getFullName() for _,scriptName in ipairs(sorted) do combo:addOption(scriptName) if scriptName == scriptNameScene then combo.selected = #combo.options end end combo = ISComboBox:new(10, 10, width, height, self, self.onComboEdit) combo:initialise() combo:instantiate() self:addChild(combo) self.editCombo = combo self.editUI = {} self.editUI.current = nil local ui = EditChassis:new(10, combo:getBottom() + 10, 250, 400) ui:setVisible(false) self:addChild(ui) self.editUI.chassis = ui ui = EditArea:new(10, combo:getBottom() + 10, 250, 400) ui:setVisible(false) self:addChild(ui) self.editUI.area = ui ui = EditAttachment:new(10, combo:getBottom() + 10, 250, 400) ui:setVisible(false) self:addChild(ui) self.editUI.attachment = ui ui = EditPassenger:new(10, combo:getBottom() + 10, 250, 400) ui:setVisible(false) self:addChild(ui) self.editUI.passenger = ui ui = EditPhysics:new(10, combo:getBottom() + 10, 250, 400) ui:setVisible(false) self:addChild(ui) self.editUI.physics = ui ui = EditWheel:new(10, combo:getBottom() + 10, 250, 400) ui:setVisible(false) self:addChild(ui) self.editUI.wheel = ui combo:addOptionWithData("Chassis", self.editUI.chassis) combo:addOptionWithData("Areas", self.editUI.area) combo:addOptionWithData("Attachments", self.editUI.attachment) combo:addOptionWithData("Passengers", self.editUI.passenger) combo:addOptionWithData("Physics", self.editUI.physics) combo:addOptionWithData("Wheels", self.editUI.wheel) local buttonHgt = FONT_HGT_MEDIUM + 8; local button = ISButton:new(10, self.bottomPanel.height - 10 - buttonHgt, 80, buttonHgt, "SAVE", self, self.onSave) self.bottomPanel:addChild(button) local button2 = ISButton:new(button:getRight() + 10, button.y, 80, buttonHgt, "EXIT", self, self.onExit) self.bottomPanel:addChild(button2) local button3 = ISButton:new(10, button.y - 10 - buttonHgt, 80 * 2 + 10, buttonHgt, "RELOAD ALL", self, self.onReload) self.bottomPanel:addChild(button3) local label = ISLabel:new(10, self.bottomPanel.y - 30, FONT_HGT_SMALL, "", 1, 1, 1, 1, UIFont.Small, true) label:setAnchorTop(false) label:setAnchorBottom(true) self:addChild(label) self.wroteScriptLabel = label self:alignEverythingToGrid() self.editUI.attachment:doLayout() self:setEditUI(self.editUI.chassis) end function EditVehicleUI:onResolutionChange(oldw, oldh, neww, newh) self:setWidth(neww) self:setHeight(newh) self.scriptCombo:setX(self.width / 2 - self.scriptCombo.width / 2) self.bottomPanel:setX(self.width / 2 - self.bottomPanel.width / 2) self.editUI.attachment:doLayout() end function EditVehicleUI:update() ISPanel.update(self) if self.width ~= getCore():getScreenWidth() or self.height ~= getCore():getScreenHeight() then self:onResolutionChange(self.width, self.height, getCore():getScreenWidth(), getCore():getScreenHeight()) end end function EditVehicleUI:prerender() ISPanel.prerender(self) --[[ local vehicle = getEditVehicleState():fromLua0("getVehicle") self.scene:setVehicle(vehicle) for _,view in ipairs(self.views) do view:setVehicle(vehicle) end --]] self.scene:prerenderEditor() if self.editUI and self.editUI.current then self.editUI.current:prerenderEditor() end if (self.wroteScriptLabel.name ~= "") and (self.wroteScriptTime + 5000 < getTimestampMs()) then self.wroteScriptLabel:setName("") end end function EditVehicleUI:onComboEdit() local ui = self.editCombo:getOptionData(self.editCombo.selected) self:setEditUI(ui) end function EditVehicleUI:onComboVehicle() local scriptName = self.scriptCombo:getOptionText(self.scriptCombo.selected) self:setScript(scriptName) end function EditVehicleUI:setScript(scriptName) self.scene.javaObject:fromLua2("setVehicleScript", "vehicle", scriptName) for _,view in ipairs(self.views) do view.javaObject:fromLua2("setVehicleScript", "vehicle1", scriptName) end self:alignEverythingToGrid() self:setEditUI(self.editUI.current) end function EditVehicleUI:setEditUI(ui) self.scene.javaObject:fromLua2("setObjectVisible", "character", false) if self.editUI.current then self.editUI.current:setVisible(false) end self.editUI.current = ui if ui then ui:toUI() ui:setVisible(true) end end function EditVehicleUI:alignEverythingToGrid() local script = self.scene.javaObject:fromLua1("getVehicleScript", "vehicle") alignVectorToGrid(script:getModel():getOffset()) alignVectorToGrid(script:getCenterOfMassOffset()) alignExtentsToGrid(script:getExtents()) alignExtentsToGrid(script:getPhysicsChassisShape()) for i=1,script:getAreaCount() do alignAreaToGrid(script:getArea(i-1)) end for i=1,script:getWheelCount() do alignVectorToGrid(script:getWheel(i-1):getOffset()) end for i=1,script:getPassengerCount() do local pngr = script:getPassenger(i-1) for j=1,pngr:getPositionCount() do alignVectorToGrid(pngr:getPosition(j-1):getOffset()) end end end function EditVehicleUI:onSave(button, x, y) local script = self.scene.javaObject:fromLua1("getVehicleScript", "vehicle") getEditVehicleState():fromLua1("writeScript", script:getFullName()) script:toBullet() end function EditVehicleUI:onExit(button, x, y) getEditVehicleState():fromLua0("exit") end function EditVehicleUI:onReload(button, x, y) local script = self.scene.javaObject:fromLua1("getVehicleScript", "vehicle") local scriptName = script:getFullName() reloadVehicles() self:setScript(scriptName) end -- Called from Java function EditVehicleUI:showUI() local scriptNameScene = self.scene.javaObject:fromLua1("getVehicleScript", "vehicle"):getFullName() self.scriptCombo:select(scriptNameScene) end -- Called from Java function EditVehicleUI:wroteScript(fileName) self.wroteScriptTime = getTimestampMs() self.wroteScriptLabel:setName(fileName) end function EditVehicleUI:new(x, y, width, height) local o = ISPanel.new(self, x, y, width, height) o:setAnchorRight(true) o:setAnchorBottom(true) o:noBackground() getEditVehicleState():setTable(o) return o end -- Called from Java function EditVehicleState_InitUI() local UI = EditVehicleUI:new(0, 0, getCore():getScreenWidth(), getCore():getScreenHeight()) EditVehicleState_UI = UI UI:setVisible(true) UI:addToUIManager() end