Related
Below is the code I am referring to, and the first recursive call # checkDirections(grid, i - 1, j) is giving me a StackOverFlow error. I understand that this means the code is not hitting the base case, but I do not understand why.
class Solution {
public int orangesRotting(int[][] grid) {
int rowLength = grid.length;
int colLength = grid[0].length;
int minMinutes = 0;
for (int i = 0; i < rowLength; i++) {
for (int j = 0; j < colLength; j++) {
if (grid[i][j] == 2) {
checkDirections(grid, i, j);
}
}
}
return minMinutes;
}
public void checkDirections(int[][] grid, int i, int j) {
if ((i < 0 || i > grid.length || j < 0 || j > grid[0].length) || grid[i][j] == 0) {
return;
} else if (grid[i][j] == 1) {
grid[i][j] = 2;
return;
}
//check left
checkDirections(grid, i - 1, j);
//check right
checkDirections(grid, i + 1, j);
//check up
checkDirections(grid, i, j - 1);
//check down
checkDirections(grid, i, j + 1);
}
}
I'm trying to block the x and y data from dropping under zero.
Nothing has come to my mind.
void serialEvent() {
serialData = Serial.readString();
serX.write(parseDataX(serialData));
serY.write(parseDataY(serialData));
}
int parseDataX(String data) {
data.remove(data.indexOf("Y"));
data.remove(data.indexOf("X"), 1);
return data.toInt();
}
void loop(){
if (parseDataX < 0){
parseDataX(String data) = int(0);
}
}
int parseDataY(String data) {
data.remove(0, data.indexOf("Y") + 1);
return data.toInt();
}
Just want to stop x and y when they drop below zero.
You can do the check inside serialEvent():
void serialEvent() {
serialData = Serial.readString();
int x = parseDataX(serialData);
if(x < 0)
x = 0;
int y = parseDataY(serialData);
if(y < 0)
y = 0;
serX.write(x);
serY.write(y);
}
Or you could return 0 from the parsefunctions.
I have data from a camera in mono 8bit.
This is converted into an int vector using
std::vector<int> grayVector(size);
// convert / copy pointer data into vector: 8 bit
if (static_cast<XI_IMG_FORMAT>(format) == XI_MONO8)
{
quint8* imageIterator = reinterpret_cast<quint8*> (pMemVoid);
for (size_t count = 0; count < size; ++count)
{
grayVector[count] = static_cast<int>(*imageIterator);
imageIterator++;
}
}
Next, I need to convert this into a QImage. If I set the image format to QImage::Format_Mono the app crashes. With QImage::Format_RGB16 I get strippes, and with QImage::Format_RGB32 everything is black.
I would like to know how to do this the best, efficient and correct way?
// convert gray values into QImage data
QImage image = QImage(static_cast<int>(sizeX), static_cat<int>(sizeY), QImage::Format_RGB16);
for ( int y = 0; y < sizeY; ++y )
{
int yoffset = sizeY*y;
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y)) ;
for ( int x = 0; x < sizeX ; ++x )
{
int pos = x + yoffset;
int color = grayVector[static_cast<size_t>(pos)];
*line++ = qRgb(color, color, color);
}
}
The conversion to int is unnecessary and you do it in a very inefficient way; all you need is to use the QImage::Format_Grayscale8 available since Qt 5.5 (mid-2015).
Anyway, what you really want is a way to go from XI_IMG to QImage. The default BP_UNSAFE buffering policy should be adequate - the QImage will do a format conversion, so taking the data from XiApi's internal buffer is OK. Thus the following - all of the conversions are implemented in Qt and are quite efficient - much better than most any naive code.
I didn't check whether some Xi formats may need a BGR swap. If so, then the swap can be set to true in the format selection code and the rest will happen automatically.
See also: xiAPI manual.
static QVector<QRgb> grayScaleColorTable() {
static QVector<QRgb> table;
if (table.isEmpty()) {
table.resize(256);
auto *data = table.data();
for (int i = 0; i < table.size(); ++i)
data[i] = qRgb(i, i, i);
}
return table;
}
constexpr QImage::Format grayScaleFormat() {
return (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
? QImage::Format_Grayscale8
: QImage::Format_Indexed8;
}
QImage convertToImage(const XI_IMG *src, QImage::Format f) {
Q_ASSERT(src->fmt == XI_MONO16);
Q_ASSERT((src->padding_x % 2) == 0);
if (src->fmt != XI_MONO16) return {};
const quint16 *s = static_cast<const quint16*>(src->bp);
const int s_pad = src->padding_x/2;
if (f == QImage::Format_BGR30 ||
f == QImage::Format_A2BGR30_Premultiplied ||
f == QImage::Format_RGB30 ||
f == QImage::Format_A2RGB30_Premultiplied)
{
QImage ret{src->width, src->height, f};
Q_ASSERT((ret->bytesPerLine() % 4) == 0);
const int d_pad = ret->bytesPerLine()/4 - ret->width();
quint32 *d = (quint32*)ret.bits();
if (s_pad == d_pad) {
const int N = (src->width + s_pad) * src->height - s_pad;
for (int i = 0; i < N; ++i) {
quint32 const v = (*s++) >> (16-10);
*d++ = 0xC0000000 | v << 20 | v << 10 | v;
}
} else {
for (int j = 0; j < src->height; ++j) {
for (int i = 0; i < src->width; ++i) {
quint32 const v = (*s++) >> (16-10);
*d++ = 0xC0000000u | v << 20 | v << 10 | v;
}
s += s_pad;
d += d_pad;
}
}
return ret;
}
QImage ret{src->width, src->height, grayScaleFormat()};
const int d_pad = ret->bytesPerLine() - ret->width();
auto *d = ret.bits();
if (s_pad == d_pad) {
const int N = (src->width + s_pad) * src->height - s_pad;
for (int i = 0; i < N; ++i) {
*d++ = (*s++) >> 8;
} else {
for (int j = 0; j < src->height; ++j) {
for (int i = 0; i < src->width; ++i)
*d++ = (*s++) >> 8;
s += s_pad;
d += d_pad;
}
}
return ret;
}
QImage fromXiImg(const XI_IMG *src, QImage::Format dstFormat = QImage::Format_ARGB32Premultiplied) {
Q_ASSERT(src->width > 0 && src->height > 0 && src->padding_x >= 0 && src->bp_size > 0);
Q_ASSERT(dstFormat != QImage::Format_Invalid);
bool swap = false;
int srcPixelBytes = 0;
bool externalConvert = false;
QImage::Format srcFormat = QImage::Format_Invalid;
switch (src->fmt) {
case XI_MONO8:
srcPixelBytes = 1;
srcFormat = grayScaleFormat();
break;
case XI_MONO16:
srcPixelBytes = 2;
externalConvert = true;
break;
case XI_RGB24:
srcPixelBytes = 3;
srcFormat = QImage::Format_RGB888;
break;
case XI_RGB32:
srcPixelBytes = 4;
srcFormat = QImage::Format_RGB32;
break;
};
if (srcFormat == QImage::Format_Invalid && !externalConvert) {
qWarning("Unhandled XI_IMG image format");
return {};
}
Q_ASSERT(srcPixelBytes > 0 && srcPixelBytes <= 4);
int bytesPerLine = src->width * srcPixelBytes + src->padding_x;
if ((bytesPerLine * src->height - src->padding_x) > src->bp_size) {
qWarning("Inconsistent XI_IMG data");
return {};
}
QImage ret;
if (!externalConvert)
ret = QImage{static_cast<const uchar*>(src->bp), src->width, src->height,
bytesPerLine, srcFormat};
else
ret = convertToImage(src, dstFormat);
if (ret.format() == QImage::Format_Indexed8)
ret.setColorTable(grayScaleColorTable());
if (ret.format() != dstFormat)
ret = std::move(ret).convertToFormat(dstFormat);
if (swap)
ret = std::move(ret).rgbSwapped();
if (!ret.isDetached()) // ensure that we don't share XI_IMG's data buffer
ret.detach();
return ret;
}
I've stumbled upon a strange behavior inside my Vulkan application (based on Qt, but it shouldn't matter).
When my Vulkan window gets resized I need to recreate the swapchain. I use vkGetPhysicalDeviceSurfaceCapabilitiesKHR() to get new information about the window surface (which is not being recreated, which might or might not be a problem) and receive the new surface extents: currentExtent = { 46, 0 } with minImageExtent = { 1, 1 }. In other words, Vulkan wants me to create a 0 height swapchain while simultaneously 1x1 being the minimum allowed.
Assuming that the driver knows what it's doing, I proceed along and later I get a debug report stating that some internal "vkCreateImage failed", and after that Vulkan crashes leaving only death and destruction. How to handle that? Should I constrain currentExtent to min and max? Or am I missing something?
EDIT:
As the comments suggest, I'm copy-pasting parts of the code responsible for this. What I've noticed is that the OS actually resizes the window to 46x0 at some point, for some reason.
void QtWindow::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
scheduleSwapchainRecreation();
}
void QtWindow::scheduleSwapchainRecreation()
{
std::lock_guard<std::mutex> lock{mSwapchainRecreationMutex};
if (mSwapchainRecreationScheduled)
return;
mSwapchainRecreationScheduled = true;
QMetaObject::invokeMethod(this, "recreateSwapchain", Qt::QueuedConnection);
}
void QtWindow::recreateSwapchain()
{
std::lock_guard<std::mutex> lock{mStateMutex};
checkVkResult(vkDeviceWaitIdle(mDevice));
createSwapchain();
// state mutex should also cover swapchain recreation
mSwapchainRecreationScheduled = false;
}
void QtWindow::createSwapchain()
{
mSwapchain = makeUnique<VulkanSwapchain>(mMemoryManager,
width(),
height(),
mInstance,
mPhysicalDevice,
mDevice,
mSurface,
mPresentationQueueFamily,
mPresentationQueue,
mMemoryManager,
mSwapchain.get());
const auto min = mSwapchain->getMinExtent();
const auto max = mSwapchain->getMaxExtent();
setMinimumSize({ static_cast<int>(min.width), static_cast<int>(min.height) });
setMaximumSize({ static_cast<int>(max.width), static_cast<int>(max.height) });
}
The swapchain class:
VulkanSwapchain::VulkanSwapchain(uint32_t width,
uint32_t height,
VkInstance instance,
VkPhysicalDevice physicalDevice,
const VulkanDevice &device,
VkSurfaceKHR surface,
uint32_t presentationQueueFamily,
VkQueue presentationQueue,
const MemoryManagerPtr &memoryManager,
VulkanSwapchain *oldSwapchain)
: mInstance{instance}
, mDevice{device}
, mSurface{surface}
, mPresentQueue{presentationQueue}
, mDetails{{},{{}, memoryManager},{{}, memoryManager}}
, mSwapchainImages{memoryManager}
, mSwapchainImageViews{memoryManager}
, mMainCommandBuffers{memoryManager}
{
createSwapchain(width, height, physicalDevice, presentationQueueFamily, memoryManager, oldSwapchain);
createSwapchainImageViews();
createSemaphores();
createMainCommandPool();
}
VulkanSwapchain::~VulkanSwapchain()
{
if (mMainCommandPool != VK_NULL_HANDLE)
vkDestroyCommandPool(mDevice, mMainCommandPool, nullptr);
vkDestroySemaphore(mDevice, mAcquireSemaphore, nullptr);
for (const auto view : mSwapchainImageViews)
vkDestroyImageView(mDevice, view, nullptr);
if (mSwapchain != VK_NULL_HANDLE)
vkDestroySwapchainKHR(mDevice, mSwapchain, nullptr);
if (mSurface != VK_NULL_HANDLE)
vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
}
VkResult VulkanSwapchain::acquire() noexcept
{
return vkAcquireNextImageKHR(mDevice, mSwapchain, UINT64_MAX, mAcquireSemaphore, VK_NULL_HANDLE, &mAcquiredImageIndex);
}
VkResult VulkanSwapchain::present(VkSemaphore renderingFinishedSemaphore) noexcept
{
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &renderingFinishedSemaphore;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &mSwapchain;
presentInfo.pImageIndices = &mAcquiredImageIndex;
return vkQueuePresentKHR(mPresentQueue, &presentInfo);
}
void VulkanSwapchain::createSwapchain(uint32_t width,
uint32_t height,
VkPhysicalDevice physicalDevice,
uint32_t presentationQueueFamily,
const MemoryManagerPtr &memoryManager,
VulkanSwapchain *oldSwapchain)
{
GE_LOG << L"Creating swapchain..." << std::endl;
querySwapchainDetails(physicalDevice);
chooseSwapchainSurfaceFormat();
const auto chosenPresentMode = chooseSwapchainPresentMode();
chooseSwapchainExtents(width, height);
// triple or double buffering
auto imageCount = (chosenPresentMode == VK_PRESENT_MODE_MAILBOX_KHR) ? (3u) : (2u);
if (imageCount < mDetails.mCapabilities.minImageCount)
imageCount = mDetails.mCapabilities.minImageCount;
else if (mDetails.mCapabilities.maxImageCount > 0 && imageCount > mDetails.mCapabilities.maxImageCount)
imageCount = mDetails.mCapabilities.maxImageCount;
GE_LOG << L"Chosen surface format: " << mSwapchainFormat.format << L' ' << mSwapchainFormat.colorSpace << std::endl;
GE_LOG << L"Chosen present mode: " << chosenPresentMode << std::endl;
GE_LOG << L"Chosen extents: " << mExtent.width << L'x' << mExtent.height << std::endl;
GE_LOG << L"Image count: " << imageCount << std::endl;
VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = mSurface;
createInfo.minImageCount = imageCount;
createInfo.imageFormat = mSwapchainFormat.format;
createInfo.imageColorSpace = mSwapchainFormat.colorSpace;
createInfo.imageExtent = mExtent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
createInfo.preTransform = mDetails.mCapabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = chosenPresentMode;
createInfo.clipped = VK_TRUE;
if (oldSwapchain != nullptr)
createInfo.oldSwapchain = *oldSwapchain;
const auto graphicsQueueFamily = mDevice.getGraphicsQueueFamily();
if (graphicsQueueFamily != presentationQueueFamily)
{
uint32_t queueFamilyIndices[] = { graphicsQueueFamily, presentationQueueFamily };
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
}
else
{
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
checkVkResult(vkCreateSwapchainKHR(mDevice, &createInfo, nullptr, &mSwapchain));
uint32_t swapchainImageCount = 0;
checkVkResult(vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, nullptr));
mSwapchainImages.resize(swapchainImageCount);
checkVkResult(vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, mSwapchainImages.data()));
}
void VulkanSwapchain::querySwapchainDetails(VkPhysicalDevice physicalDevice)
{
checkVkResult(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &mDetails.mCapabilities));
uint32_t numSurfaceFormats = 0;
checkVkResult(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &numSurfaceFormats, nullptr));
if (numSurfaceFormats == 0)
BOOST_THROW_EXCEPTION(RenderingModule::Exception{"Cannot find surface formats."});
mDetails.mSurfaceFormats.resize(numSurfaceFormats);
checkVkResult(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &numSurfaceFormats, mDetails.mSurfaceFormats.data()));
uint32_t numPresentModes = 0;
checkVkResult(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface, &numPresentModes, nullptr));
if (numPresentModes == 0)
BOOST_THROW_EXCEPTION(RenderingModule::Exception{"Cannot find presentation modes."});
mDetails.mPresentModes.resize(numPresentModes);
checkVkResult(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface, &numPresentModes, mDetails.mPresentModes.data()));
}
void VulkanSwapchain::chooseSwapchainExtents(uint32_t width, uint32_t height)
{
if (mDetails.mCapabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
mExtent.width = mDetails.mCapabilities.currentExtent.width;
else
mExtent.width = std::min(std::max(mDetails.mCapabilities.minImageExtent.width, width), mDetails.mCapabilities.maxImageExtent.width);
if (mDetails.mCapabilities.currentExtent.height != std::numeric_limits<uint32_t>::max())
mExtent.height = mDetails.mCapabilities.currentExtent.height;
else
mExtent.height = std::min(std::max(mDetails.mCapabilities.minImageExtent.height, height), mDetails.mCapabilities.maxImageExtent.height);
}
void VulkanSwapchain::chooseSwapchainSurfaceFormat()
{
VkSurfaceFormatKHR desiredSurfaceFormat = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
if (mDetails.mSurfaceFormats.size() == 1 && mDetails.mSurfaceFormats[0].format == VK_FORMAT_UNDEFINED)
{
mSwapchainFormat = desiredSurfaceFormat;
}
else
{
auto found = false;
for (const auto &format : mDetails.mSurfaceFormats)
{
if (format.format == desiredSurfaceFormat.format && format.colorSpace == desiredSurfaceFormat.colorSpace)
{
mSwapchainFormat = format;
found = true;
break;
}
}
if (!found)
{
// try without color space
for (const auto &format : mDetails.mSurfaceFormats)
{
if (format.format == desiredSurfaceFormat.format)
{
mSwapchainFormat = format;
found = true;
break;
}
}
if (!found)
mSwapchainFormat = mDetails.mSurfaceFormats.front();
}
}
}
void VulkanSwapchain::createSwapchainImageViews()
{
mSwapchainImageViews.resize(mSwapchainImages.size());
VkImageViewCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.format = mSwapchainFormat.format;
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.layerCount = 1;
for (auto i = 0u; i < mSwapchainImages.size(); ++i)
{
createInfo.image = mSwapchainImages[i];
checkVkResult(vkCreateImageView(mDevice, &createInfo, nullptr, &mSwapchainImageViews[i]));
}
}
void VulkanSwapchain::createSemaphores()
{
VkSemaphoreCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
checkVkResult(vkCreateSemaphore(mDevice, &createInfo, nullptr, &mAcquireSemaphore));
}
void VulkanSwapchain::createMainCommandPool()
{
VkCommandPoolCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
createInfo.queueFamilyIndex = mDevice.getGraphicsQueueFamily();
checkVkResult(vkCreateCommandPool(mDevice, &createInfo, nullptr, &mMainCommandPool));
mMainCommandBuffers.resize(mSwapchainImageViews.size());
VkCommandBufferAllocateInfo allocateInfo = {};
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocateInfo.commandPool = mMainCommandPool;
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocateInfo.commandBufferCount = static_cast<uint32_t>(mMainCommandBuffers.size());
checkVkResult(vkAllocateCommandBuffers(mDevice, &allocateInfo, mMainCommandBuffers.data()));
}
VkPresentModeKHR VulkanSwapchain::chooseSwapchainPresentMode() const
{
VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR;
QSettings settings;
if (!settings.value(swapIntervalSettingName, true).toBool())
{
for (const auto mode : mDetails.mPresentModes)
{
if (mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
{
chosenPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
break;
}
}
}
#if (defined(Q_OS_WIN) && !defined(Q_OS_WINPHONE)) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
else if (settings.value(tripleBufferingSettingName, true).toBool())
{
// reduce latency on desktops, but preserve battery life on mobile
for (const auto mode : mDetails.mPresentModes)
{
if (mode == VK_PRESENT_MODE_MAILBOX_KHR)
{
chosenPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
}
}
#endif
return chosenPresentMode;
}
I am writing a game. By tick timer should work the this slot.
void game_process::animate_cell(MainWindow* m, const std::string& s, double x,double y, size_t i, size_t j, const std::string& step)
{
painter.begin(m);
std::string ss("C:\\Users\\Vardan\\GAmes_lines\\res\\red_" + step + ".png");
ss += s;
const char* p = ss.c_str();
QImage image(p);
RECT temp = cal
culate_cell_rect(i, j);
QRectF target(x, y, image.width(), image.height());
painter.drawImage(target, image);
painter.end();
m->update(x + temp.x0, y + temp.y0, 60, 60);
}
, that's it,
QTimer * timer = new QTimer (this);
connect (timer, SIGNAL (timeout ()), this, SLOT (render_cell (MainWindow * m, const std :: string & s, double x, double y, size_t i, size_t j, const std :: string & step))); timer-> start ();
But as you can see the slot more parameters than the signal, and hence signals and slots mechanism does not work. What to do?
Here cod
#include <QDesktopWidget>
#include <QResizeEvent>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <phonon/MediaObject>
#include <phonon/MediaSource>
#include <phonon/AudioOutput>
#include <utility>
#include <cassert>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
QImage image("C:\\Users\\Vardan\\GAmes_lines\\res\\back_3.png");
m_width = 1000;
m_height = 800;
m_game_width = image.width();
m_game_height = image.height();
setFixedSize(m_width, m_height);
m_click_coords.first = 0;
m_click_coords.second = 0;
m_timer_tick = false;
m_timer_id = 0;
setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
m_area_x0_coordinate = (this->width() - image.width())/2;
m_area_y0_coordinate = (this->height() - image.height())/2;
m_r = new game_process(m_area_x0_coordinate, m_area_y0_coordinate, image.width()/*+30*/, image.height()/*+30*/, 57);
m_status = false;
Phonon::MediaObject *mediaobject = new Phonon::MediaObject;
QString filename("C://Users//Vardan//GAmes_lines//music//Casino Ambiance Music.wav");
mediaobject->setCurrentSource(filename);
Phonon::AudioOutput *audio = new Phonon::AudioOutput;
Phonon::createPath(mediaobject,audio);
mediaobject->play();
QPixmap pixmap("C:\\Users\\Vardan\\GAmes_lines\\res\\background.png");
QPalette palette;
palette.setBrush(/*this->backgroundRole()*/QPalette::Background, QBrush(pixmap));
this->setPalette(palette);
}
MainWindow::MainWindow(std::string& str, QWidget *parent):
QWidget(parent)
{
}
double MainWindow::get_mouse_click_absolute_x_coordinate() const
{
return m_area_x0_coordinate;
}
double MainWindow::get_mouse_click_absolute_y_coordinate() const
{
return m_area_y0_coordinate;
}
void MainWindow::set_mouse_click_absolute_x_coordinate(double x)
{
m_area_x0_coordinate = x;
}
void MainWindow::set_mouse_click_absolute_y_coordinate(double y)
{
m_area_y0_coordinate = y;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
if(m_status == false)
{
m_r->game_loop(this);
}
else
{
game_process::RECT temp = m_r->calculate_cell_rect(m_click_coords.first, m_click_coords.second);
int x = m_area_x0_coordinate + temp.x0;
int y = m_area_y0_coordinate + temp.y0;
std::pair<double, double> p;
/////////////////////////////////////////////////////////
start_timer();
//////////////////////////////////////////////////////////
for(int i = 2; i < 8; ++i)
{
char buf[sizeof(int)];
itoa(i, buf, 10);
std::string s(buf);
m_r->erase_frame(this, x, y);
while(m_timer_tick == false){}
p = m_r->draw_frame(this, m_click_coords.first, m_click_coords.second, s.c_str());
m_timer_tick = false;
}
end_timer();
m_status = false;
}
}
bool MainWindow::delay(int ms)
{
QTime dieTime = QTime::currentTime().addMSecs(ms);
while( QTime::currentTime() < dieTime )
return true;
}
void MainWindow::mousePressEvent (QMouseEvent* e)
{
qDebug() << "Local:" << e->pos().x();
qDebug() << "Local:" << e->pos().y();
std::pair<double, double> p = m_r->calculate_index_of_the_coordinates(e->pos().x(), e->pos().y(), m_width, m_height);
if(m_area_x0_coordinate <= e->pos().x() && m_area_y0_coordinate <= e->pos().y()
&& m_area_x0_coordinate + m_game_width >= e->pos().x() && m_area_y0_coordinate + m_game_height >= e->pos().y() )
{
m_status = true;
m_click_coords.first = p.first;
m_click_coords.second = p.second;
game_process::RECT coords = m_r->calculate_cell_rect(p.first, p.second);
Figure* f = m_r->detect_figure_by_index(p.first, p.second);
m_r->delete_cluster(this, f);
}
game_process::RECT r;
qDebug() << "Local:" << p.first;
qDebug() << "Local:" << p.second;
}
void MainWindow::timerEvent(QTimerEvent *event)
{
m_timer_tick = true;
}
void MainWindow::start_timer()
{
m_timer_id = startTimer(1000 / 30);
}
void MainWindow::end_timer()
{
killTimer(m_timer_id);
}
bool MainWindow::event(QEvent *e)
{
switch (e->type())
{
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
return true;
}
return QWidget::event(e);
}
I noticed that the timer does not start from paintEvent, and I need what he started with paintEvent. What to do?
I adjusted the code following your advice.
#include "mainwindow.h"
#include "game_process.h"
#include <QPixmap>
#include <QPainter>
#include <QPalette>
#include <QDesktopWidget>
#include <QResizeEvent>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <phonon/MediaObject>
#include <phonon/MediaSource>
#include <phonon/AudioOutput>
#include <utility>
#include <cassert>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
QImage image("C:\\Users\\Vardan\\GAmes_lines\\res\\back_3.png");
m_width = 1000;
m_height = 800;
m_game_width = image.width();
m_game_height = image.height();
setFixedSize(m_width, m_height);
m_click_coords.first = 0;
m_click_coords.second = 0;
m_next_cell = 0;
m_frame_count = 2;
m_timer_tick = false;
m_timer_id = 0;
m_matrix_size = 0;
m_timer_flag = false;
setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
m_area_x0_coordinate = (this->width() - image.width())/2;
m_area_y0_coordinate = (this->height() - image.height())/2;
m_r = new game_process(m_area_x0_coordinate, m_area_y0_coordinate, image.width()/*+30*/, image.height()/*+30*/, 57);
m_status = false;
Phonon::MediaObject *mediaobject = new Phonon::MediaObject;
QString filename("C://Users//Vardan//GAmes_lines//music//Casino Ambiance Music.wav");
mediaobject->setCurrentSource(filename);
Phonon::AudioOutput *audio = new Phonon::AudioOutput;
Phonon::createPath(mediaobject,audio);
mediaobject->play();
QPixmap pixmap("C:\\Users\\Vardan\\GAmes_lines\\res\\background.png");
QPalette palette;
palette.setBrush(/*this->backgroundRole()*/QPalette::Background, QBrush(pixmap));
this->setPalette(palette);
}
MainWindow::~MainWindow()
{
}
MainWindow::MainWindow(std::string& str, QWidget *parent):
QWidget(parent)
{
}
double MainWindow::get_mouse_click_absolute_x_coordinate() const
{
return m_area_x0_coordinate;
}
double MainWindow::get_mouse_click_absolute_y_coordinate() const
{
return m_area_y0_coordinate;
}
void MainWindow::set_mouse_click_absolute_x_coordinate(double x)
{
m_area_x0_coordinate = x;
}
void MainWindow::set_mouse_click_absolute_y_coordinate(double y)
{
m_area_y0_coordinate = y;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
static int ind = 0;
if(m_status == false && m_timer_tick != true)
{
m_r->game_loop(this);
}
else
{
std::pair<double, double> p;
int x = 0;
int y = 0;
static int s = m_r->get_close_map_size();
static std::vector<std::pair<int, int> > v = m_r->get_close_map_indexes();
if(m_frame_count >= 7)
{
m_frame_count = 2;
++m_next_cell;
if(m_next_cell <= v.size())
{
game_process::RECT temp = m_r->calculate_cell_rect(v[m_next_cell].second, v[m_next_cell].first);
x = m_area_x0_coordinate + temp.x0;
y = m_area_y0_coordinate + temp.y0;
m_x = x;
m_y = y;
}
}
if(m_next_cell == 0)
{
game_process::RECT temp = m_r->calculate_cell_rect(v[m_next_cell].second, v[m_next_cell].first);
x = m_area_x0_coordinate + temp.x0;
y = m_area_y0_coordinate + temp.y0;
m_x = x;
m_y = y;
}
if(m_frame_count < 7 && m_next_cell < v.size())
{
char buf[sizeof(int)];
itoa(m_frame_count, buf, 10);
std::string s(buf);
m_r->erase_frame(this, x, y);
p = m_r->draw_frame(this, v[m_next_cell].second, v[m_next_cell].first, s.c_str());
m_timer_tick = false;
c = true;
}
if(c == false && m_next_cell > v.size() - 1)
{
end_timer();
qDebug()<<"m_x = " << m_x;
qDebug()<<"m_y = " << m_y;
qDebug()<<"m_frame_count + 1 = " << m_frame_count + 1;
qDebug()<<"v.size() = " << v.size();
m_r->repaint_cells(this);
}
m_status = false;
}
}
void MainWindow::mousePressEvent (QMouseEvent* e)
{
qDebug() << "Local:" << e->pos().x();
qDebug() << "Local:" << e->pos().y();
std::pair<double, double> p = m_r->calculate_index_of_the_coordinates(e->pos().x(), e->pos().y(), m_width, m_height);
if(m_area_x0_coordinate <= e->pos().x() && m_area_y0_coordinate <= e->pos().y()
&& m_area_x0_coordinate + m_game_width >= e->pos().x() && m_area_y0_coordinate + m_game_height >= e->pos().y() )
{
start_timer();
m_status = true;
m_click_coords.first = p.first;
m_click_coords.second = p.second;
game_process::RECT coords = m_r->calculate_cell_rect(p.first, p.second);
Figure* f = m_r->detect_figure_by_index(p.first, p.second);
m_r->delete_cluster(this, f);
//this->update(m_area_x0_coordinate + coords.x0, m_area_y0_coordinate + coords.y0, 57, 57);
}
game_process::RECT r;
qDebug() << "Local:" << p.first;
qDebug() << "Local:" << p.second;
}
void MainWindow::timerEvent(QTimerEvent *event)
{
if(event->timerId() == m_timer_id)
{
m_timer_tick = true;
++m_frame_count;
if(m_x >=0 && m_y >=0)
{
qDebug()<<"m_x "<<m_x <<"m_y "<<m_y<<"time |||||| Passed";
this->update(m_x, m_y, 60, 60);
}
}
else
{
QWidget::timerEvent(event);
}
}
void MainWindow::start_timer()
{
m_timer_id = startTimer(50);
}
void MainWindow::end_timer()
{
killTimer(m_timer_id);
}
bool MainWindow::event(QEvent *e)
{
switch (e->type())
{
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
return true;
}
return QWidget::event(e);
}
Here's the code repaint_cells()
void game_process::repaint_cells(MainWindow* m)
{
Figure* f = 0;
for(int i = 0; i < 8; ++i)
{
for(int j = 0; j < 8; ++j)
{
if(m_close_list[j][i] == -1)
{
f = create_new_figure(j, i);
m_figures.push_back(f);
assert(f != 0);
draw_figure(m, f, i, j);
m_close_list[j][i] = 0;
}
}
}
}
enter link description here
For two days I can not understand why only one ball is drawn. Тhe remaining balls are not drawn.
You have two main approaches:
Simply define another slot with no parameters that will call game_process::render_cell(), then connect to the new slot.
If you're using Qt 5, use a lambda. See here for examples. It would look something like this: connect(timer, &QTimer::timeout, [=](){/*call the function here*/});
I recommend #2.
I see from your code snippet that you are passing a pointer to MainWindow to your render_cell() function, which I assume is some kind of widget or class derived from QObject.
In that case you could override the timerEvent(), which is defined for each QObject class and implement your game loop here. This way the parameters of your render_cell() could be be member variables of MainWindow, or your entire game_process class could be embedded in MainWindow.
Also, I think this approach is a little faster than using signals, which might be important for code that has to render something 30-60 times per second and update a bunch of other things.
For documentation see http://qt-project.org/doc/qt-4.8/qobject.html#timerEvent
In pseudo code, you could implement your game like this:
class MainWindow : public QWidget
{
private:
game_process *game;
int timer_id;
public:
MainWindow(void)
: QWidget(0),
game(0),
timer_id(0)
{
game = new game_process;
}
void startGame(void)
{
timer_id = startTimer(1000 / 30); // 30 fps
}
void endGame(void)
{
killTimer(timer_id);
}
protected:
virtual void timerEvent(QTimerEvent *event)
{
// update AI
// update network
// render game
game->render_cell(/* params */);
}
};