cocos2d slot machine animation - objective-c

I am trying to create an application that simulates a slot machine.
Now, I have all the images ready, with the vertical png file and the plist file. My question is, how do I simulate the spinning (when the user presses a button), and then the stopping of the slot machine (after around 1-2 seconds)?
Note that the png file has to wrap around somehow.
Everything else is all a matter of NSArrays and checking, what I want to figure out is the animation. I hope some can share some code or references to do this.
Thanks!

This is relatively straightforward: just repeat the png file as many times as you need to simulate the spinning action. So it's basically a vertical variation on parallax scrolling. If you have Steffan Itterheim's book, he talks about this type of thing in chapter 7 "Scrolling With Joy". You may also find some help here: Cocos2D vertically scrolling background
Hope this helps!
Mike

I am doing something like this:
#include <ctime>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
using namespace std;
static int last[5]={0, 0, 0, 0, 0};
static int stops[5];
static int reels[5][63] = {
{9,7,12,5,7,3,4,11,9,7,12,6,7,4,11,10,4,3,11,12,7,5,10,9,7,5,9,10,8,9,7,4,9,10,11,5,10,3,9,10,3,9,4,8,7,5,11,9,12,6,3,5,7,9,11,10,6,7,3,5,10,8,4,},
{11,5,4,7,6,8,4,9,7,8,3,11,6,5,11,7,12,5,8,6,10,9,5,6,8,7,12,11,5,6,10,3,4,5,9,12,8,9,6,5,12,8,9,12,7,8,5,10,12,7,11,3,4,8,7,4,5,9,8,6,12,4,6,},
{10,4,5,8,6,7,5,9,6,7,8,4,6,5,11,3,9,8,7,11,12,6,8,5,4,8,6,12,9,6,5,11,3,7,4,8,7,3,10,9,5,6,4,3,9,12,10,8,9,6,3,9,10,6,7,5,6,8,4,11,9,7,8,},
{9,3,6,5,3,10,6,9,5,12,4,8,11,10,7,6,5,9,7,3,8,6,12,4,5,7,3,12,10,6,9,7,8,5,6,4,9,6,11,5,8,12,6,7,3,6,10,3,7,5,10,8,9,6,12,4,7,9,5,6,8,3,10,},
{5,3,9,4,6,12,10,5,11,4,8,7,10,5,9,11,4,6,7,3,6,4,8,5,11,8,5,10,8,11,5,10,8,3,7,4,10,11,5,7,8,9,5,11,6,8,10,3,7,9,3,8,10,12,6,8,10,11,7,10,8,11,6,},
};
static SDL_Window *window = NULL;
static SDL_Surface *canvas = NULL;
static const SDL_Surface *backgroundSurface = IMG_Load("./Background.png");
static SDL_Rect backgroundCoordinates = { 0, 0, 0, 0 };
static const SDL_Surface *symbolsSurface[] = {
NULL,
NULL,
NULL,
IMG_Load("./Symbol03.png"),
IMG_Load("./Symbol04.png"),
IMG_Load("./Symbol05.png"),
IMG_Load("./Symbol06.png"),
IMG_Load("./Symbol07.png"),
IMG_Load("./Symbol08.png"),
IMG_Load("./Symbol09.png"),
IMG_Load("./Symbol10.png"),
IMG_Load("./Symbol11.png"),
IMG_Load("./Symbol12.png"),
NULL,
NULL,
NULL,
NULL,
};
static const SDL_Surface *reelsSurface[5] = {NULL, NULL, NULL, NULL, NULL};
static SDL_Rect symbolsCoordinates[5][3] = {
{ { 298, 118, 0, 0 }, { 298, 266, 0, 0 }, { 298, 414, 0, 0 } },
{ { 474, 118, 0, 0 }, { 474, 266, 0, 0 }, { 474, 414, 0, 0 } },
{ { 651, 118, 0, 0 }, { 651, 266, 0, 0 }, { 651, 414, 0, 0 } },
{ { 827, 118, 0, 0 }, { 827, 266, 0, 0 }, { 827, 414, 0, 0 } },
{ { 1003, 118, 0, 0 }, { 1003, 266, 0, 0 }, {1003, 414, 0, 0 } },
};
static unsigned long animationStart = 0;
static unsigned long animationEnd = 0;
static bool stopped[5] = {false, false, false, false, false};
void draw() {
static double y0 = 0;
static double v0[5] = {-9.5, -9.6, -9.7, -9.8, -9.9};
static long t = 0;
static double a = 0.0005;
static int y = 0;
SDL_BlitSurface((SDL_Surface*) backgroundSurface, NULL, canvas, &backgroundCoordinates);
for (int i = 0; i < 5 && animationStart!=animationEnd; i++) {
/*
* y = y0 + v0*t + 1/2*at^2
*/
y0 = last[i] * 140;
t = (1000 * clock() / CLOCKS_PER_SEC) - animationStart;
y = (int)(y0 + v0[i]*t + a*t*t/2) % (63*140);
if(y < 0) {
y += 63*140;
}
/*
* Stop near to the target position.
*/
if(i==0 && abs(y-stops[i]*140)<=140) {
last[i] = stops[i];
stopped[i] = true;
}else if(stopped[i-1] == true && stopped[i] == false && abs(y-stops[i]*140)<=140) {
last[i] = stops[i];
stopped[i] = true;
}
if(stopped[i] == true) {
SDL_SetSurfaceAlphaMod((SDL_Surface*) reelsSurface[i], 255);
y = stops[i] * 140;
} else {
SDL_SetSurfaceAlphaMod((SDL_Surface*) reelsSurface[i], 191);
}
const SDL_Rect frame = {0, y, 140, 3*140};
SDL_BlitSurface((SDL_Surface*) reelsSurface[i], &frame, canvas, &symbolsCoordinates[i][0]);
}
SDL_UpdateWindowSurface(window);
}
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
/*
* Build long strips (two more images at the end).
*/
for(int i=0, index; i<5; i++) {
reelsSurface[i] = IMG_Load("./Reel.png");
for(int j=0; j<(63+2); j++) {
index = reels[i][j%63];
SDL_Rect coordinates = {0, 140*j, 0, 0};
SDL_BlitSurface((SDL_Surface*) symbolsSurface[index], NULL, (SDL_Surface*)reelsSurface[i], &coordinates);
}
}
//window = SDL_CreateWindow("Slot Reels Animation", 0, 0, 1280, 1024, SDL_WINDOW_FULLSCREEN_DESKTOP);
window = SDL_CreateWindow("Slot Reels Animation", 0, 0, 1440, 900, 0);
canvas = SDL_GetWindowSurface(window);
SDL_Event event;
bool done = false;
while (done == false) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
done = true;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
done = true;
break;
case SDLK_RETURN:
//startAnimation();
memset(stopped, false, 5*sizeof(bool));
animationStart = 1000 * clock() / CLOCKS_PER_SEC;
for (int i = 0, r; i < 5; i++) {
stops[i] = rand() % 63;
}
break;
}
}
}
draw();
}
SDL_DestroyWindow(window);
for(int i=0; i<5; i++) {
SDL_FreeSurface((SDL_Surface*)reelsSurface[i]);
}
SDL_Quit();
return EXIT_SUCCESS;
}

Related

For loop inside a Redis queue does not work as expected in NestJs

I have the following code, basically it is doing a bruteforce on a key of a hash in the first 4 bytes. Then I loop through each of these positions to test all possible combinations. If I put this code inside the service it runs normally and takes about 200 seconds to find all possible combinations of the first 4 bytes.
But when you're doing long operations, it's good to have a queue to do this in the background. That's what I did, I added it to a nestjs queue with redis but inside the queue when I use for it seems that they are shuffled and they all end together in less than 5 seconds, besides that I don't find the correct combination. And if I use a forEach it either doesn't work or the program crashes during execution.
Basically the first 4 bytes are [192, 156, 127, 0, ...] but it doesn't find it when it's inside a queue. How can I make the background queue run normally as if it were in the service?
import * as crypto from 'crypto';
const DIFFICULTY = {
legendary: {
maxValues: [255, 255, 255, 1],
},
hard: {
maxValues: [255, 255, 255, 0],
},
medium: {
maxValues: [255, 255, 127, 0],
},
easy: {
maxValues: [255, 255, 64, 0],
},
};
#Processor('decrypt-queue')
export class DecryptConsumer {
constructor(
#InjectRepository(Chest) private readonly repository: Repository<Chest>,
) {}
#Process('decrypt-job')
async decryptJob(job: Job) {
const code = job.data;
await job.progress(50);
const chest = await this.repository.findOne({
where: {
code: code,
},
});
await this.repository.save({
...chest,
status: ChestStatus.Oppening,
});
const iv = Buffer.from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
const original = chest.key;
const range = ({
from = 0,
to,
step = 1,
length = Math.ceil((to - from) / step),
}): number[] => Array.from({ length }, (_, i) => from + i * step);
const first = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[0],
step: 1,
});
const second = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[1],
step: 1,
});
const third = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[2],
step: 1,
});
let four = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[3],
step: 1,
});
four = [0];
// first.forEach(async (i) => {
// second.forEach(async (j) => {
// third.forEach(async (k) => {
// four.forEach(async (l) => {
// console.log(i, j, k, l);
// if (
// i === original[0] &&
// j === original[1] &&
// k === original[2] &&
// l === original[3]
// ) {
// console.log(i, j, k, l, end());
// const decipher = await crypto.createDecipheriv(
// 'aes-128-cbc',
// Buffer.from([i, j, k, l, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
// iv,
// );
// let decrypted = await decipher.update(code, 'hex', 'utf8');
// decrypted += decipher.final('utf8');
// if (decrypted.includes('Hello')) {
// await this.repository.save({
// ...chest,
// status: ChestStatus.Openned,
// });
// await job.progress(100);
// // return {
// // decrypted,
// // };
// } else {
// }
// }
// });
// });
// });
// });
for (let i = 0; i < DIFFICULTY[chest.difficulty].maxValues[0]; i++) {
for (let j = 0; j < DIFFICULTY[chest.difficulty].maxValues[1]; j++) {
for (let k = 0; k < DIFFICULTY[chest.difficulty].maxValues[2]; k++) {
for (let l = 0; l < DIFFICULTY[chest.difficulty].maxValues[3]; l++) {
if (
i === original[0] &&
j === original[1] &&
k === original[2] &&
l === original[3]
) {
console.log(i, j, k, l, end());
const decipher = await crypto.createDecipheriv(
'aes-128-cbc',
Buffer.from([i, j, k, l, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
iv,
);
let decrypted = await decipher.update(code, 'hex', 'utf8');
decrypted += decipher.final('utf8');
if (decrypted.includes('Hello')) {
await this.repository.save({
...chest,
status: ChestStatus.Openned,
});
await job.progress(100);
// return {
// decrypted,
// };
} else {
}
}
}
}
}
}
await this.repository.save({
...chest,
status: ChestStatus.Locked,
});
await job.progress(100);
// return {
// decrypted: false,
// };
}
}

Drawing color and depth images side by side in Vulkan

I'm currently learning Vulkan and I'm trying to write an application that draws a scene and the scene's depth buffer side by side.
At first I thought to use a single subpass to render a frame with extent (width/2) x height and then use vkCmdBlitImage twice to copy the resulting frame and its depth image to the swapchain but I quickly discovered that swapchain images don't necessarily support VK_IMAEG_USAGE_TRANSFER_DST_BIT.
My current strategy is to use two subpasses in a single render pass.
The first subpass renders the resulting frame to the left side of the screen using a viewport and the second subpass takes the depth attachment of the first subpass as an input attachment and renders it to the right side of the screen.
My first issue is that this strategy seems incredibly wasteful because I have to use a depth image whose extent is width x height (instead of (width/2) x height) so if it were up to you, how would you implement this application?
My second issue is that the depth image isn't showing at all!
The color attachment is showing just fine on the left (and it also shows fine on the right if I switch between the viewports) but on the right (where the depth image should be) I get a clearValue-colored screen.
The depth buffer itself is working just fine (The objects on the screen are rendered in the correct order) and it also looks like the fragment shader is working fine (I tried writing different colors without using the input attachment and it worked).
I am running out of ideas where the problem could be, I think it's something to do with the subpass dependency becuase it looks like the depth values aren't getting written to the buffer (or are accessed before they are written).
Relevant code:
/***************/
/* Render pass */
/***************/
{
const VkAttachmentDescription attachments[] = {
// Color attachment
{
.flags = 0,
.format = swapchain->format,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
//.stencilLoadOp = <uninitialized>,
//.stencilStoreOp = <uninitialized>,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
},
// Depth attachment / Input attachment
{
.flags = 0,
.format = VK_FORMAT_D32_SFLOAT,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
},
};
const VkSubpassDescription subpasses[] = {
// First subpass - Render "regular" frame
{
.flags = 0,
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
//.pInputAttachments = <uninitialized>,
.colorAttachmentCount = 1,
.pColorAttachments = (VkAttachmentReference[]) {
{ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL },
},
.pResolveAttachments = NULL,
.pDepthStencilAttachment = (VkAttachmentReference[]) {
{ 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL },
},
.preserveAttachmentCount = 0,
//.pPreserveAttachments = <uninitialized>,
},
// Second subpass - Render depth image
{
.flags = 0,
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 1,
.pInputAttachments = (VkAttachmentReference[]) {
{ 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL },
},
.colorAttachmentCount = 1,
.pColorAttachments = (VkAttachmentReference[]) {
{ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL },
},
.pResolveAttachments = NULL,
.pDepthStencilAttachment = NULL,
.preserveAttachmentCount = 0,
//.pPreserveAttachments = <uninitialized>,
},
};
const VkSubpassDependency dependencies[] = {
{
.srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0,
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
},
{
.srcSubpass = 0,
.dstSubpass = 1,
.srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
},
};
const VkRenderPassCreateInfo create_info = {
.flags = 0,
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
.pAttachments = attachments,
.subpassCount = sizeof(subpasses) / sizeof(subpasses[0]),
.pSubpasses = subpasses,
.dependencyCount = sizeof(dependencies) / sizeof(dependencies[0]),
.pDependencies = dependencies,
};
vulkan_result = vkCreateRenderPass(device, &create_info, NULL,
&swapchain->renderPass);
assert(vulkan_result == VK_SUCCESS);
}
/**************************/
/* Descriptor set layouts */
/**************************/
{
// MVP matrices
VkDescriptorSetLayoutCreateInfo create_info = {
.flags = 0,
.bindingCount = 1,
.pBindings = (VkDescriptorSetLayoutBinding[]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.pImmutableSamplers = NULL,
}
},
};
vulkan_result = vkCreateDescriptorSetLayout(device, &create_info, NULL, &renderer->setLayouts.color);
assert(vulkan_result == VK_SUCCESS);
// Input attachment for depth image
create_info.pBindings = (VkDescriptorSetLayoutBinding[]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = NULL,
}
};
vulkan_result = vkCreateDescriptorSetLayout(device, &create_info, NULL, &renderer->setLayouts.depth);
assert(vulkan_result == VK_SUCCESS);
}
/********************/
/* Pipeline layouts */
/********************/
{
VkPipelineLayoutCreateInfo create_info = {
.flags = 0,
.setLayoutCount = 1,
.pSetLayouts = &renderer->setLayouts.color,
.pushConstantRangeCount = 0,
//.pPushConstantRanges = <uninitialized>,
};
vulkan_result = vkCreatePipelineLayout(device, &create_info, NULL, &renderer->pipelineLayouts.color);
assert(vulkan_result == VK_SUCCESS);
create_info.pSetLayouts = &renderer->setLayouts.depth;
vulkan_result = vkCreatePipelineLayout(device, &create_info, NULL, &renderer->pipelineLayouts.depth);
assert(vulkan_result == VK_SUCCESS);
}
/*************/
/* Pipelines */
/*************/
{
size_t code_size;
uint32_t *code;
code = read_file("shaders/color_vert.spv", &code_size);
VkShaderModuleCreateInfo shader_module_create_info = {
.flags = 0,
.codeSize = code_size,
.pCode = code,
};
VkShaderModule vertex_module;
vulkan_result = vkCreateShaderModule(device, &shader_module_create_info, NULL, &vertex_module);
free(code);
assert(vulkan_result == VK_SUCCESS);
code = read_file("shaders/color_frag.spv", &code_size);
if (code == NULL) {
vkDestroyShaderModule(device, vertex_module, NULL);
}
shader_module_create_info.codeSize = code_size;
shader_module_create_info.pCode = code;
VkShaderModule fragment_module;
vulkan_result = vkCreateShaderModule(device, &shader_module_create_info, NULL, &fragment_module);
assert(vulkan_result == VK_SUCCESS);
free(code);
VkPipelineShaderStageCreateInfo stages[] = {
{
.flags = 0,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vertex_module,
.pName = "main",
.pSpecializationInfo = NULL,
},
{
.flags = 0,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = fragment_module,
.pName = "main",
.pSpecializationInfo = NULL,
}
};
const VkVertexInputBindingDescription vertex_binding_description = {
.binding = 0,
.stride = sizeof(struct Vertex),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
};
const VkVertexInputAttributeDescription vertex_attribute_description[] = {
// Position
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(struct Vertex, position),
},
// Color
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(struct Vertex, color),
}
};
VkPipelineVertexInputStateCreateInfo vertex_input_state = {
.flags = 0,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &vertex_binding_description,
.vertexAttributeDescriptionCount = sizeof(vertex_attribute_description) / sizeof(vertex_attribute_description[0]),
.pVertexAttributeDescriptions = vertex_attribute_description,
};
VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
.flags = 0,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE,
};
VkPipelineViewportStateCreateInfo viewport_state = {
.flags = 0,
.viewportCount = 1,
.pViewports = (VkViewport[]) {
{
.x = 0.0f,
.y = 0.0f,
.width = (float) extent.width / 2,
.height = (float) extent.height,
.minDepth = 0.0f,
.maxDepth = 1.0f,
},
},
.scissorCount = 1,
.pScissors = (VkRect2D[]) {
{
.offset = { 0, 0 },
.extent = { extent.width / 2, extent.height },
},
},
};
VkPipelineRasterizationStateCreateInfo rasterization_state = {
.flags = 0,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
//.depthBiasConstantFactor = ,
//.depthBiasClamp = ,
//.depthBiasSlopeFactor = ,
.lineWidth = 1.0f,
};
const VkPipelineMultisampleStateCreateInfo multisample_state = {
.flags = 0,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
.sampleShadingEnable = VK_FALSE,
.minSampleShading = 1.0f,
.pSampleMask = NULL,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,
};
VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {
.flags = 0,
.depthTestEnable = VK_TRUE,
.depthWriteEnable = VK_TRUE,
.depthCompareOp = VK_COMPARE_OP_LESS,
.depthBoundsTestEnable = VK_FALSE,
.stencilTestEnable = VK_FALSE,
//.front = <uninitialized>,
//.back = <uninitialized>,
//.minDepthBounds = <uninitialized>,
//.maxDepthBounds = <uninitialized>,
};
const VkPipelineColorBlendAttachmentState attachments[] = {
{
.blendEnable = VK_FALSE,
//.srcColorBlendFactor = <uninitialized>,
//.dstColorBlendFactor = <uninitialized>,
//.colorBlendOp = <uninitialized>,
//.srcAlphaBlendFactor = <uninitialized>,
//.dstAlphaBlendFactor = <uninitialized>,
//.alphaBlendOp = <uninitialized>,
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
}
};
const VkPipelineColorBlendStateCreateInfo color_blend_state = {
.flags = 0,
.logicOpEnable = VK_FALSE,
//.logicOp = <uninitialized>,
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
.pAttachments = attachments,
//.blendConstants[4] = <uninitialized>,
};
VkGraphicsPipelineCreateInfo create_info = {
.flags = 0,
.stageCount = sizeof(stages) / sizeof(stages[0]),
.pStages = stages,
.pVertexInputState = &vertex_input_state,
.pInputAssemblyState = &input_assembly_state,
.pTessellationState = NULL,
.pViewportState = &viewport_state,
.pRasterizationState = &rasterization_state,
.pMultisampleState = &multisample_state,
.pDepthStencilState = &depth_stencil_state,
.pColorBlendState = &color_blend_state,
.pDynamicState = NULL,
.layout = renderer->pipelineLayouts.color,
.renderPass = render_pass,
.subpass = 0,
//.basePipelineHandle = ,
//.basePipelineIndex = ,
};
vulkan_result = vkCreateGraphicsPipelines(device, NULL, 1, &create_info, NULL, &renderer->pipelines.color);
assert(vulkan_result == VK_SUCCESS);
vkDestroyShaderModule(device, fragment_module, NULL);
vkDestroyShaderModule(device, vertex_module, NULL);
code = read_file("shaders/depth_vert.spv", &code_size);
assert(code != NULL);
shader_module_create_info.codeSize = code_size;
shader_module_create_info.pCode = code;
vulkan_result = vkCreateShaderModule(device, &shader_module_create_info, NULL, &vertex_module);
assert(vulkan_result == VK_SUCCESS);
free(code);
code = read_file("shaders/depth_frag.spv", &code_size);
assert(code != NULL);
shader_module_create_info.codeSize = code_size;
shader_module_create_info.pCode = code;
vulkan_result = vkCreateShaderModule(device, &shader_module_create_info, NULL, &fragment_module);
assert(vulkan_result == VK_SUCCESS);
free(code);
stages[0].module = vertex_module;
stages[1].module = fragment_module;
vertex_input_state.vertexBindingDescriptionCount = 0;
vertex_input_state.vertexAttributeDescriptionCount = 0;
viewport_state.pViewports = (VkViewport[]) {
{
.x = (float) extent.width / 2,
.y = 0.0f,
.width = (float) extent.width / 2,
.height = (float) extent.height,
.minDepth = 0.0f,
.maxDepth = 1.0f,
},
};
viewport_state.pScissors = (VkRect2D[]) {
{
.offset = { extent.width / 2, 0 },
.extent = { extent.width / 2, extent.height },
}
};
rasterization_state.cullMode = VK_CULL_MODE_NONE;
create_info.pDepthStencilState = NULL;
create_info.layout = renderer->pipelineLayouts.depth;
create_info.subpass = 1;
vulkan_result = vkCreateGraphicsPipelines(device, NULL, 1, &create_info, NULL, &renderer->pipelines.depth);
vkDestroyShaderModule(device, vertex_module, NULL);
vkDestroyShaderModule(device, fragment_module, NULL);
assert(vulkan_result == VK_SUCCESS);
}
/****************/
/* Depth images */
/****************/
{
// renderer->depthImages is a wrapper around VkImage and VkImageView
// renderer->depthImages.images is a VkImage array with image_count elements
// renderer->depthImages.imagesViews are the views of the respective images
wn_images_init(renderer->device /* also includes physical device for memory allocation */, image_count, VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, extent, &renderer->depthImages);
}
/****************/
/* Framebuffers */
/****************/
{
renderer->framebuffers = calloc(sizeof(VkFramebuffer), renderer->imageCount);
assert(renderer->framebuffers != NULL);
if (renderer->framebuffers == NULL) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
for (uint32_t i = 0; i < renderer->imageCount; i++) {
const VkImageView attachments[] = {
render_targets[i],
renderer->depthImages.imagesViews[i],
};
const VkFramebufferCreateInfo create_info = {
.flags = 0,
.renderPass = render_pass,
.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
.pAttachments = attachments,
.width = extent.width,
.height = extent.height,
.layers = 1,
};
vulkan_result = vkCreateFramebuffer(device, &create_info, NULL,
renderer->framebuffers + i);
assert(vulkan_result == VK_SUCCESS);
}
}
/******************/
/* Uniform buffers */
/******************/
{
wn_buffer_init(renderer->device, sizeof(struct UniformBufferObject) * renderer->imageCount,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&renderer->uniformBuffer.buffers);
}
/*******************/
/* Descriptor pool */
/*******************/
{
const VkDescriptorPoolSize pool_sizes[] = {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, renderer->imageCount },
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, renderer->imageCount },
};
const VkDescriptorPoolCreateInfo create_info = {
.flags = 0,
.maxSets = renderer->imageCount * 2,
.poolSizeCount = sizeof(pool_sizes) / sizeof(pool_sizes[0]),
.pPoolSizes = pool_sizes,
};
assert(vkCreateDescriptorPool(device, &create_info, NULL, &renderer->descriptorPool) == VK_SUCCESS);
}
/*******************/
/* Descriptor sets */
/*******************/
{
VkDescriptorSetLayout layouts[renderer->imageCount];
for (uint32_t i = 0; i < renderer->imageCount; i++) {
layouts[i] = renderer->setLayouts.color;
}
VkDescriptorSetAllocateInfo allocate_info = {
.descriptorPool = renderer->descriptorPool,
.descriptorSetCount = renderer->imageCount,
.pSetLayouts = layouts,
};
renderer->sets.color = calloc(renderer->imageCount, sizeof(VkDescriptorSet));
assert(renderer->sets.color != NULL);
vulkan_result = vkAllocateDescriptorSets(device, &allocate_info, renderer->sets.color);
assert(vulkan_result == VK_SUCCESS);
for (uint32_t i = 0; i < renderer->imageCount; i++) {
layouts[i] = renderer->setLayouts.depth;
}
renderer->sets.depth = calloc(renderer->imageCount, sizeof(VkDescriptorSet));
assert(renderer->sets.depth != NULL);
vulkan_result = vkAllocateDescriptorSets(device, &allocate_info, renderer->sets.depth);
assert(vulkan_result == VK_SUCCESS);
for (uint32_t i = 0; i < renderer->imageCount; i++) {
const VkDescriptorBufferInfo buffer_info = {
.buffer = renderer->uniformBuffer.buffers.buffer,
.offset = sizeof(struct UniformBufferObject) * i,
.range = sizeof(struct UniformBufferObject),
};
const VkDescriptorImageInfo image_info = {
.sampler = VK_NULL_HANDLE,
.imageView = renderer->depthImages.imagesViews[i],
.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
};
const VkWriteDescriptorSet writes[] = {
{
.dstSet = renderer->sets.color[i],
.dstBinding = 0,
//.dstArrayElement = <uninitialized>,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
//.pImageInfo = <uninitialized>,
.pBufferInfo = &buffer_info,
//.pTexelBufferView = <uninitialized>,
},
{
.dstSet = renderer->sets.depth[i],
.dstBinding = 0,
//.dstArrayElement = <uninitialized>,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
.pImageInfo = &image_info,
//.pBufferInfo = <uninitialized>,
//.pTexelBufferView = <uninitialized>,
},
};
vkUpdateDescriptorSets(device, sizeof(writes) / sizeof(writes[0]), writes, 0, NULL);
}
}
/*******************/
/* Command buffers */
/*******************/
{
renderer->commandBuffers = calloc(renderer->imageCount, sizeof(VkCommandBuffer));
if (renderer->commandBuffers == NULL)
return VK_ERROR_OUT_OF_HOST_MEMORY;
const VkCommandBufferAllocateInfo allocate_info = {
.commandPool = renderer->graphicsCommandPool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = renderer->imageCount,
};
vkAllocateCommandBuffers(device, &allocate_info, renderer->commandBuffers);
const VkCommandBufferBeginInfo begin_info = {
.flags = 0
//.pInheritanceInfo = <uninitialized>,
};
for (uint32_t i = 0; i < renderer->imageCount; i++) {
vkBeginCommandBuffer(renderer->commandBuffers[i], &begin_info);
const VkRenderPassBeginInfo render_pass_begin_info = {
.renderPass = render_pass,
.framebuffer = renderer->framebuffers[i],
.renderArea = {
.offset = { 0, 0 },
.extent = { extent.width, extent.height },
},
.clearValueCount = 2,
.pClearValues = (VkClearValue[]) {
{ { { 0.2f, 0.2f, 0.2f, 1.0f } } }, // Grey background
{ { { 1.0f, /*<uninitialized>*/ } } },
},
};
vkCmdBeginRenderPass(renderer->commandBuffers[i], &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(renderer->commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipelines.color);
// Vertex and index buffers are in one VkBuffer. First the vertices and then the indices
vkCmdBindVertexBuffers(renderer->commandBuffers[i], 0, 1, &renderer->vertexIndexBuffer.buffer, (VkDeviceSize[]) { 0 });
vkCmdBindIndexBuffer(renderer->commandBuffers[i], renderer->vertexIndexBuffer.buffer, sizeof(vertices), VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(renderer->commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipelineLayouts.color, 0, 1, renderer->sets.color + i, 0, NULL);
vkCmdDrawIndexed(renderer->commandBuffers[i], sizeof(indices) / sizeof(indices[0]), 1, 0, 0, 0);
vkCmdNextSubpass(renderer->commandBuffers[i], VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(renderer->commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipelines.depth);
vkCmdBindDescriptorSets(renderer->commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipelineLayouts.depth, 0, 1, renderer->sets.depth + i, 0, NULL);
vkCmdDraw(renderer->commandBuffers[i], 3, 1, 0, 0);
vkCmdEndRenderPass(renderer->commandBuffers[i]);
vkEndCommandBuffer(renderer->commandBuffers[i]);
}
}
Iv'e tried to cut the code as much as possible so sType and pNext should all be assumed to be correct.
depth_vert.spv:
#version 450
void main()
{
gl_Position = vec4(vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2) * 2.0f - 1.0f, 0.0f, 1.0f);
}
depth_frag.spv:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(input_attachment_index = 0, binding = 0) uniform subpassInput inDepth;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(vec3((subpassLoad(inDepth).r - 0.8) / 0.2), 1.0f);
}

webgl texture on expo gives black screen

I'm trying webGL for the first time, thing is I am working on Expo with the expo-gl package, aiming to build a filter component for photo editing. So far, I have been able to create a context successfully. When creating the shaders everything works fine (I can render a triangle, two triangles, etc...)
Problem comes when I try to load an image as a texture, I get no errors, but all I get is a black screen on the emulator and the phone (both android).
I have done checks for powOf2 images and image.onload, and I did a console.log for gl.texImage2D but got undefined. I would really appreciate any insight or help for this issue.
I divided into 4 parts what I think are the relevant pieces of code for this issue.
1.shaders(template literals):
const vertexShaderSource = '
attribute vec2 a_texCoord;
attribute vec4 a_position;
varying vec2 v_texCoord;
void main() {
gl_Position = a_position;
v_texCoord = a_texCoord;
}
';
const fragmentShaderSource = '
precision mediump float;
uniform sampler2D u_image;
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
';
2.ReactNative(expo) state and lifecicle:
export default class App extends React.Component {
state = {
ready: false,
image: null,
};
componentDidMount() {
(async () => {
const image = Asset.fromModule(require('./bw.jpg'));
await image.downloadAsync();
this.setState({
ready: true,
image,
});
})();
}
render() {
return (
<View style={styles.container}>
<Image source={require('./back.jpg')} style={{ width: '100%' }} />
<GLView
style={{ width: '100%', height: '100%', position: 'absolute' }}
onContextCreate={this._onContextCreate}
/>
</View>
);
}
3.gl context:
_onContextCreate = gl => {
if (_initialized) { return }
function createShader(gl, type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
//on error
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
//get shaders
var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
//on error
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
//create program
var program = createProgram(gl, vertexShader, fragmentShader);
//get attributes
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
//a_position buffer for fragment shader
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// three 2d points
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
-1, 1,
1, -1,
1, 1,
1, -1,
-1, 1,
]), gl.STATIC_DRAW);
//create the viewport
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
// Clear the canvas
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// use program
gl.useProgram(program);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(
positionAttributeLocation, 2, gl.FLOAT, false, 0, 0)
gl.drawArrays(gl.TRIANGLES, 0, 6);
4.Code for the texture, and end of _onContextCreate:
//get image from state
const image = this.state.image
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
var uSampler = gl.getUniformLocation(program, 'u_image');
// provide texture coordinates for the rectangle.
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
var positions = [
-1,-1,
-1, 1,
1,-1,
1, 1,
1,-1,
-1, 1,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
//create texture
var texture = gl.createTexture();
//check if image is ready
if (image.downloaded) loadTexture(texture, image)
//get image width & height for pow2 check.
const { width, height } = Image.resolveAssetSource(image);
function loadTexture(texture, img) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(uSampler, 0);
//pow2 check
if (isPowerOf2(width) && isPowerOf2(height)) {
gl.generateMipmap(gl.TEXTURE_2D);
} else {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
}
return texture
}
function isPowerOf2(value) {
return (value & (value - 1)) == 0;
}
gl.flush();
gl.endFrameEXP();
_initialized = true;
};
Thanks in advance!

react-native requestanimationframe - flicker - freeze - app crash

am learning to build app using react-native and below is the component code that am using. The problem is - when I simulate this app - it crashes in few seconds. I couldnt understand what is causing this problem. Can someone please suggest.
I am trying to animate a canvas circle using requestAnimationFrame in this component.
Thank you ..
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Dimensions
} from 'react-native';
import Canvas from 'react-native-canvas';
export default class ThreeDiscs extends Component{
constructor(props){
super(props);
this.state = {
context: null,
screen: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height
},
a: 0,
b: 0,
c: 100,
d: 100
};
this.coordinates = {
a: 0,
b: 0,
c: 100,
d: 100
};
this.directions = {
increment: 5,
direction: 0
};
this.discs = [
{
x: 150,
y: 250,
lastX: 150,
lastY: 250,
velocityX: -3.2,
velocityY: 3.5,
radius: 10,
innerColor: 'rgba(255,255,0,1)',
middleColor: 'rgba(255,255,0,0.7)',
outerColor: 'rgba(255,255,0,0.5)',
strokeStyle: 'gray',
}
];
this.numDiscs = this.discs.length;
}
rendercanvas = (canvas) => {
canvas.width = this.state.screen.width;
canvas.height = this.state.screen.height;
const context = canvas.getContext('2d');
this.setState({context: context});
context.fillStyle = 'purple';
context.fillRect(0,0,100,100);
this.drawBackground(context);
this.update(context);
this.draw(context);
this.animatecanvas(context);
}
drawBackground(context) {
var STEP_Y = 12,
i = this.state.screen.height;
context.strokeStyle = 'lightgray';
context.lineWidth = 0.5;
while(i > STEP_Y*4) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
i -= STEP_Y;
}
context.save();
context.strokeStyle = 'rgba(100,0,0,0.3)';
context.lineWidth = 1;
context.beginPath();
context.moveTo(35,0);
context.lineTo(35,context.canvas.height);
context.stroke();
context.restore();
}
update(context) {
var disc = null;
for(var i=0; i < this.numDiscs; ++i) {
disc = this.discs[i];
if (disc.x + disc.velocityX + disc.radius > context.canvas.width ||
disc.x + disc.velocityX - disc.radius < 0)
disc.velocityX = -disc.velocityX;
if (disc.y + disc.velocityY + disc.radius > context.canvas.height ||
disc.y + disc.velocityY - disc.radius < 0)
disc.velocityY= -disc.velocityY;
disc.x += disc.velocityX;
disc.y += disc.velocityY;
}
}
draw(context) {
var disc = this.discs[i];
for(var i=0; i < this.numDiscs; ++i) {
disc = this.discs[i];
context.save();
context.beginPath();
context.arc(disc.x, disc.y, disc.radius, 0, Math.PI*2, false);
context.fillStyle = '#000';
context.strokeStyle = disc.strokeStyle;
context.fill();
context.stroke();
context.restore();
}
}
animatecanvas(context){
context.clearRect(0,0,this.state.screen.width,this.state.screen.height);
this.drawBackground(context);
this.update(context);
this.draw(context);
requestAnimationFrame(() => {this.animatecanvas(context)});
}
render(){
return(
<Canvas ref={this.rendercanvas} />
);
}
}

Is there are more elegant Solution for a large switch statement?

I have got map a lot of ranges to a value like 0-300 = 10 , 300-600 = 20, 600-900 = 30 ... 2500000-2700000 = 7000 .... So I could make a really large switch-statement/if-block but I wonder if there is a more elegant approach to solve this little problem.
Ok here is a small subset of the table with real data:
0-300 : 25
301-600. : 45
601-900 : 65
901-1200. : 85
1201-1500: 105
1501-2000 : 133
2001-2500 : 161
2501-3000: 189
3001-3500:217
3501-4000:245
4001-4500:273
4501-5000:301
5001-6000:338
The most common pattern for getting rid of a switch statement is to use a dictionary. In your case, since you're mapping ranges, you'll use an NSArray of range cutoffs instead. This is what it would look like if you're dealing with ints:
NSArray *rangeCutoffs = [NSArray arrayWithObjects:[NSNumber numberWithInt:300],[NSNumberWithInt:600],...,nil];
NSArray *values = [NSArray arrayWithObjects:[NSNumber numberWithInt:10], [NSNumber numberWithInt:20],...,nil];
int mappedInt;
for (int index=0; index <= [rangeCutoffs count]; index++) {
if (intToMap < [[rangeCutoffs objectAtIndex:index] intValue]) {
mappedInt = [[values objectAtIndex:index] intValue];
}
}
if (mappedInt == 0) {
mappedInt = [[values lastObject] intValue];
}
In practice you'd want to load rangeCutoffs and values from a plist instead of hardcoding them.
You could use a table. e.g.
struct Lookup
{
int min;
int max;
int value;
};
struct Lookup table[] =
{
{ 0, 300, 10 },
{ 301, 600, 20 },
{ 601, 900, 30 },
// other ranges
{ 2500000, 2700000, 7000 },
{ -1, -1, -1 } // marks the end of the table
};
And then simply iterate through it to find the right range
int result = -1;
for (int i = 0 ; table[i].min != -1 && result == -1 ; ++i)
{
if (table[i].min <= value && value <= table[i].max)
{
result = table[i].value;
}
}
If it's a really large table, you can use a binary search instead.
You could do something like this (C example):
#include <stdio.h>
#include <stdlib.h>
typedef int range_type;
typedef int value_type;
typedef struct {
range_type min;
range_type max;
value_type value;
} range_t;
const range_t *find_range(const range_t *ranges, size_t rangesSize,
value_type valueToFind)
{
for (size_t i = 0; i < rangesSize; ++i) {
if (ranges[i].min <= valueToFind && valueToFind <= ranges[i].max)
return &ranges[i];
}
return NULL;
}
int main() {
const range_t ranges[] = {
{ 0, 300, 10 },
{ 301, 600, 20 },
{ 601, 900, 30 },
{ 901, 1200, 40 }
// And so on...
};
value_type testValues[] = {
-1, // None
0, 299, 300, // [ 0, 300]
301, 599, 600, // [301, 600]
601, 899, 900, // [601, 900]
901, 1199, 1200, // [901, 1200]
// And so on...
};
for (size_t i = 0; i < sizeof(testValues) / sizeof(testValues[0]); ++i) {
const range_t *match = find_range(
ranges, sizeof(ranges) / sizeof(ranges[0]), testValues[i]);
if (match != NULL)
printf("%d found at [%d..%d]\n", testValues[i], match->min,
match->max);
else
printf("%d not found\n", testValues[i]);
}
return EXIT_SUCCESS;
}
Should output:
-1 not found
0 found at [0..300]
299 found at [0..300]
300 found at [0..300]
301 found at [301..600]
599 found at [301..600]
600 found at [301..600]
601 found at [601..900]
899 found at [601..900]
900 found at [601..900]
901 found at [901..1200]
1199 found at [901..1200]
1200 found at [901..1200]