/* Assignment operator overloading. We signal to
	 * the references counter that we release the
	 * previous address and hold the new one */
	SmartPointer<T>& operator=(SmartPointer<T> sp) {
		unuse();
		pointer = sp.pointer;
		use();

		return *this;
	}
예제 #2
0
Program::~Program()
{
	if (m_Id == m_usedProgramId) {
		//if this program is used take care of "unusing"
		unuse();
	}
	//detach shaders
	detachAllShaders();

	//finally delete
	glDeleteProgram(m_Id);
}
예제 #3
0
	void Batch3DGeometry::render_batch() {
		
		

		//Vertices data
		glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
		glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex3D), vertices.data(), GL_STATIC_DRAW);
		//Indices data
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_vbo);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(U32), indices.data(), GL_STATIC_DRAW);

		Shader* old_shader = nullptr;
		
		U64 buffer_data_offset = 0;
		for (const auto& rb : m_render_batches){

			auto curr_shader = rb.model->material.shader;
			curr_shader->use();

			U32 old_shader_size = 0;//keep track of the size of the last used shader
			if (old_shader)old_shader_size = old_shader->attributes_struct_size;

			//If the new batch has a different shader than the one before, 
			//enable attributes and send global data
			if (old_shader != curr_shader){
				old_shader = curr_shader;
				enable_attributes(curr_shader);
				U8 curr_samp = 0;
				//Send global shader uniforms
				for (const auto& cnt : curr_shader->global_uniforms_data){
					curr_shader->send_global_uniform_to_shader(cnt.first, cnt.second.value, &curr_samp);
				}
			}

			U8 current_sampler = 0;
			
			for (const auto& cnt : rb.model->material.uniform_map)
			{
				curr_shader->send_material_uniform_to_shader(cnt.first, cnt.second, &current_sampler);
			}
		
			glBindBuffer(GL_ARRAY_BUFFER, m_i_vbo);
			glBufferData(GL_ARRAY_BUFFER, rb.num_instances * curr_shader->attributes_struct_size, (void*)((U64)input_instances + buffer_data_offset ), GL_STATIC_DRAW);
			glBindBuffer(GL_ARRAY_BUFFER, 0);
			buffer_data_offset += rb.num_instances* curr_shader->attributes_struct_size;
			U32 offset = rb.indices_offset * sizeof(U32);

			glDrawElementsInstancedBaseVertex(GL_TRIANGLES, rb.num_indices, GL_UNSIGNED_INT, (void*)offset, rb.num_instances, rb.vertex_offset);

			curr_shader->unuse();
		}
	}
예제 #4
0
void Lightmap::render(const Falltergeist::Point &pos)
{
    if (_indexes<=0) return;

    GL_CHECK(glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR));
    auto shader = ResourceManager::getInstance()->shader("lightmap");

    GL_CHECK(shader->use());

    GL_CHECK(shader->setUniform(_uniformMVP, Game::getInstance()->renderer()->getMVP()));

    // set camera offset
    GL_CHECK(shader->setUniform(_uniformOffset, glm::vec2((float)pos.x(), (float)pos.y()) ));

    GL_CHECK(shader->setUniform(_uniformFade,Game::getInstance()->renderer()->fadeColor()));


    GL_CHECK(glBindVertexArray(_vao));


    GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, _coords));
    GL_CHECK(glVertexAttribPointer(_attribPos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0 ));


    GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, _lights));

    GL_CHECK(glVertexAttribPointer(_attribLights, 1, GL_FLOAT, GL_FALSE, 0, (void*)0 ));

    GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo));


    GL_CHECK(glEnableVertexAttribArray(_attribPos));

    GL_CHECK(glEnableVertexAttribArray(_attribLights));

    GL_CHECK(glDrawElements(GL_TRIANGLES, _indexes, GL_UNSIGNED_INT, 0 ));

    GL_CHECK(glDisableVertexAttribArray(_attribPos));

    GL_CHECK(glDisableVertexAttribArray(_attribLights));

    GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
    GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
    GL_CHECK(glBindVertexArray(0));

    GL_CHECK(shader->unuse());
    GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
}
예제 #5
0
bool StGLStereoFrameBuffer::StGLStereoProgram::link(StGLContext& theCtx) {
    if(!StGLProgram::link(theCtx)) {
        return false;
    }
    StGLVarLocation uniTexLLoc = StGLProgram::getUniformLocation(theCtx, "texL");
    StGLVarLocation uniTexRLoc = StGLProgram::getUniformLocation(theCtx, "texR");
    atrVVertexLoc   = StGLProgram::getAttribLocation(theCtx, "vVertex");
    atrVTexCoordLoc = StGLProgram::getAttribLocation(theCtx, "vTexCoord");

    if(uniTexLLoc.isValid() && uniTexRLoc.isValid()) {
        use(theCtx);
        theCtx.core20fwd->glUniform1i(uniTexLLoc, StGLProgram::TEXTURE_SAMPLE_0); // GL_TEXTURE0 in multitexture
        theCtx.core20fwd->glUniform1i(uniTexRLoc, StGLProgram::TEXTURE_SAMPLE_1); // GL_TEXTURE1 in multitexture
        unuse(theCtx);
    }

    return uniTexRLoc.isValid() && uniTexLLoc.isValid() && atrVVertexLoc.isValid() && atrVTexCoordLoc.isValid();
}
	/* Signal to the references counter that we
	 * release the current address */
	~SmartPointer() {
		unuse();
	}
예제 #7
0
/**
 * Find instruction src's which are mov's that can be collapsed, replacing
 * the mov dst with the mov src
 */
static void
instr_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr)
{
	struct ir3_register *reg;

	if (instr->regs_count == 0)
		return;

	if (ir3_instr_check_mark(instr))
		return;

	/* walk down the graph from each src: */
	foreach_src_n(reg, n, instr) {
		struct ir3_instruction *src = ssa(reg);

		if (!src)
			continue;

		instr_cp(ctx, src);

		/* TODO non-indirect access we could figure out which register
		 * we actually want and allow cp..
		 */
		if (reg->flags & IR3_REG_ARRAY)
			continue;

		/* Don't CP absneg into meta instructions, that won't end well: */
		if (is_meta(instr) && (src->opc != OPC_MOV))
			continue;

		reg_cp(ctx, instr, reg, n);
	}

	if (instr->regs[0]->flags & IR3_REG_ARRAY) {
		struct ir3_instruction *src = ssa(instr->regs[0]);
		if (src)
			instr_cp(ctx, src);
	}

	if (instr->address) {
		instr_cp(ctx, instr->address);
		ir3_instr_set_address(instr, eliminate_output_mov(instr->address));
	}

	/* we can end up with extra cmps.s from frontend, which uses a
	 *
	 *    cmps.s p0.x, cond, 0
	 *
	 * as a way to mov into the predicate register.  But frequently 'cond'
	 * is itself a cmps.s/cmps.f/cmps.u.  So detect this special case and
	 * just re-write the instruction writing predicate register to get rid
	 * of the double cmps.
	 */
	if ((instr->opc == OPC_CMPS_S) &&
			(instr->regs[0]->num == regid(REG_P0, 0)) &&
			ssa(instr->regs[1]) &&
			(instr->regs[2]->flags & IR3_REG_IMMED) &&
			(instr->regs[2]->iim_val == 0)) {
		struct ir3_instruction *cond = ssa(instr->regs[1]);
		switch (cond->opc) {
		case OPC_CMPS_S:
		case OPC_CMPS_F:
		case OPC_CMPS_U:
			instr->opc   = cond->opc;
			instr->flags = cond->flags;
			instr->cat2  = cond->cat2;
			instr->address = cond->address;
			instr->regs[1] = cond->regs[1];
			instr->regs[2] = cond->regs[2];
			instr->barrier_class |= cond->barrier_class;
			instr->barrier_conflict |= cond->barrier_conflict;
			unuse(cond);
			break;
		default:
			break;
		}
	}

	/* Handle converting a sam.s2en (taking samp/tex idx params via
	 * register) into a normal sam (encoding immediate samp/tex idx)
	 * if they are immediate.  This saves some instructions and regs
	 * in the common case where we know samp/tex at compile time:
	 */
	if (is_tex(instr) && (instr->flags & IR3_INSTR_S2EN) &&
			!(ir3_shader_debug & IR3_DBG_FORCES2EN)) {
		/* The first src will be a fan-in (collect), if both of it's
		 * two sources are mov from imm, then we can
		 */
		struct ir3_instruction *samp_tex = ssa(instr->regs[1]);

		debug_assert(samp_tex->opc == OPC_META_FI);

		struct ir3_instruction *samp = ssa(samp_tex->regs[1]);
		struct ir3_instruction *tex  = ssa(samp_tex->regs[2]);

		if ((samp->opc == OPC_MOV) &&
				(samp->regs[1]->flags & IR3_REG_IMMED) &&
				(tex->opc == OPC_MOV) &&
				(tex->regs[1]->flags & IR3_REG_IMMED)) {
			instr->flags &= ~IR3_INSTR_S2EN;
			instr->cat5.samp = samp->regs[1]->iim_val;
			instr->cat5.tex  = tex->regs[1]->iim_val;
			instr->regs[1]->instr = NULL;
		}
	}
}
예제 #8
0
/**
 * Handle cp for a given src register.  This additionally handles
 * the cases of collapsing immedate/const (which replace the src
 * register with a non-ssa src) or collapsing mov's from relative
 * src (which needs to also fixup the address src reference by the
 * instruction).
 */
static void
reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
		struct ir3_register *reg, unsigned n)
{
	struct ir3_instruction *src = ssa(reg);

	if (is_eligible_mov(src, true)) {
		/* simple case, no immed/const/relativ, only mov's w/ ssa src: */
		struct ir3_register *src_reg = src->regs[1];
		unsigned new_flags = reg->flags;

		combine_flags(&new_flags, src);

		if (valid_flags(instr, n, new_flags)) {
			if (new_flags & IR3_REG_ARRAY) {
				debug_assert(!(reg->flags & IR3_REG_ARRAY));
				reg->array = src_reg->array;
			}
			reg->flags = new_flags;
			reg->instr = ssa(src_reg);

			instr->barrier_class |= src->barrier_class;
			instr->barrier_conflict |= src->barrier_conflict;

			unuse(src);
			reg->instr->use_count++;
		}

	} else if (is_same_type_mov(src) &&
			/* cannot collapse const/immed/etc into meta instrs: */
			!is_meta(instr)) {
		/* immed/const/etc cases, which require some special handling: */
		struct ir3_register *src_reg = src->regs[1];
		unsigned new_flags = reg->flags;

		combine_flags(&new_flags, src);

		if (!valid_flags(instr, n, new_flags)) {
			/* See if lowering an immediate to const would help. */
			if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
				debug_assert(new_flags & IR3_REG_IMMED);
				instr->regs[n + 1] = lower_immed(ctx, src_reg, new_flags);
				return;
			}

			/* special case for "normal" mad instructions, we can
			 * try swapping the first two args if that fits better.
			 *
			 * the "plain" MAD's (ie. the ones that don't shift first
			 * src prior to multiply) can swap their first two srcs if
			 * src[0] is !CONST and src[1] is CONST:
			 */
			if ((n == 1) && is_mad(instr->opc) &&
					!(instr->regs[0 + 1]->flags & (IR3_REG_CONST | IR3_REG_RELATIV)) &&
					valid_flags(instr, 0, new_flags & ~IR3_REG_IMMED)) {
				/* swap src[0] and src[1]: */
				struct ir3_register *tmp;
				tmp = instr->regs[0 + 1];
				instr->regs[0 + 1] = instr->regs[1 + 1];
				instr->regs[1 + 1] = tmp;

				n = 0;
			} else {
				return;
			}
		}

		/* Here we handle the special case of mov from
		 * CONST and/or RELATIV.  These need to be handled
		 * specially, because in the case of move from CONST
		 * there is no src ir3_instruction so we need to
		 * replace the ir3_register.  And in the case of
		 * RELATIV we need to handle the address register
		 * dependency.
		 */
		if (src_reg->flags & IR3_REG_CONST) {
			/* an instruction cannot reference two different
			 * address registers:
			 */
			if ((src_reg->flags & IR3_REG_RELATIV) &&
					conflicts(instr->address, reg->instr->address))
				return;

			/* This seems to be a hw bug, or something where the timings
			 * just somehow don't work out.  This restriction may only
			 * apply if the first src is also CONST.
			 */
			if ((opc_cat(instr->opc) == 3) && (n == 2) &&
					(src_reg->flags & IR3_REG_RELATIV) &&
					(src_reg->array.offset == 0))
				return;

			src_reg = ir3_reg_clone(instr->block->shader, src_reg);
			src_reg->flags = new_flags;
			instr->regs[n+1] = src_reg;

			if (src_reg->flags & IR3_REG_RELATIV)
				ir3_instr_set_address(instr, reg->instr->address);

			return;
		}

		if ((src_reg->flags & IR3_REG_RELATIV) &&
				!conflicts(instr->address, reg->instr->address)) {
			src_reg = ir3_reg_clone(instr->block->shader, src_reg);
			src_reg->flags = new_flags;
			instr->regs[n+1] = src_reg;
			ir3_instr_set_address(instr, reg->instr->address);

			return;
		}

		/* NOTE: seems we can only do immed integers, so don't
		 * need to care about float.  But we do need to handle
		 * abs/neg *before* checking that the immediate requires
		 * few enough bits to encode:
		 *
		 * TODO: do we need to do something to avoid accidentally
		 * catching a float immed?
		 */
		if (src_reg->flags & IR3_REG_IMMED) {
			int32_t iim_val = src_reg->iim_val;

			debug_assert((opc_cat(instr->opc) == 1) ||
					(opc_cat(instr->opc) == 6) ||
					ir3_cat2_int(instr->opc) ||
					(is_mad(instr->opc) && (n == 0)));

			if (new_flags & IR3_REG_SABS)
				iim_val = abs(iim_val);

			if (new_flags & IR3_REG_SNEG)
				iim_val = -iim_val;

			if (new_flags & IR3_REG_BNOT)
				iim_val = ~iim_val;

			/* other than category 1 (mov) we can only encode up to 10 bits: */
			if ((instr->opc == OPC_MOV) ||
					!((iim_val & ~0x3ff) && (-iim_val & ~0x3ff))) {
				new_flags &= ~(IR3_REG_SABS | IR3_REG_SNEG | IR3_REG_BNOT);
				src_reg = ir3_reg_clone(instr->block->shader, src_reg);
				src_reg->flags = new_flags;
				src_reg->iim_val = iim_val;
				instr->regs[n+1] = src_reg;
			} else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) {
				/* See if lowering an immediate to const would help. */
				instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags);
			}

			return;
		}
	}
}
예제 #9
0
std::shared_ptr<Texture> RenderPass::
get_buffer(std::string const& name, CameraMode mode, bool draw_fps) {

    // check for existance of desired buffer
    if ((mode == CENTER
            && center_eye_buffers_.find(name) == center_eye_buffers_.end())
     || (mode == LEFT
            && left_eye_buffers_.find(name)  == left_eye_buffers_.end())
     || (mode == RIGHT
            && right_eye_buffers_.find(name) == right_eye_buffers_.end())) {

        WARNING("Failed to get buffer \"%s\" from pass \"%s\": "
                "A buffer with this name does not exist!",
                name.c_str(), get_name().c_str());
        return NULL;
    }

    // return appropriate buffer if it has been rendered already
    if (mode == CENTER && rendererd_center_eye_)
        return center_eye_buffers_[name];

    if (mode == LEFT && rendererd_left_eye_)
        return left_eye_buffers_[name];

    if (mode == RIGHT && rendererd_right_eye_)
        return right_eye_buffers_[name];

    // serialize the scenegraph
    Optimizer optimizer;
    optimizer.check(pipeline_->get_current_graph(), render_mask_);

    // if there are dynamic texture inputs for this render pass, get the
    // according buffers recursively
    for (auto& node: optimizer.get_data().nodes_) {
        auto material(inputs_.find(node.material_));

        if (material != inputs_.end()) {
            for (auto& uniform: material->second) {
                overwrite_uniform_texture(material->first, uniform.first,
                              pipeline_->get_render_pass(uniform.second.first)->
                              get_buffer(uniform.second.second, mode));
            }
        }
    }
    // we'll need these two very often now...
    OptimizedScene const& scene(optimizer.get_data());
    RenderContext const& ctx(pipeline_->get_context());

    // get the fbo which should be rendered to
    FrameBufferObject* fbo(NULL);

    switch (mode) {
        case CENTER:
            fbo = &center_eye_fbo_;
            break;
        case LEFT:
            fbo = &left_eye_fbo_;
            break;
        case RIGHT:
            fbo = &right_eye_fbo_;
            break;
    }

    fbo->bind(ctx);

    fbo->clear_color_buffers(ctx);
    fbo->clear_depth_stencil_buffer(ctx);

    ctx.render_context->set_viewport(scm::gl::viewport(math::vec2(0,0),
                                                    math::vec2(fbo->width(),
                                                               fbo->height())));

    auto camera_it(scene.cameras_.find(camera_));
    auto screen_it(scene.screens_.find(screen_));

    if (camera_it != scene.cameras_.end()
        && screen_it != scene.screens_.end()) {

        auto camera(camera_it->second);
        auto screen(screen_it->second);

        math::mat4 camera_transform(camera.transform_);
        if (mode == LEFT) {
            scm::math::translate(camera_transform,
                                 -camera.stereo_width_*0.5f, 0.f, 0.f);
        } else if (mode == RIGHT) {
            scm::math::translate(camera_transform,
                                 camera.stereo_width_*0.5f, 0.f, 0.f);
        }

        auto projection(math::compute_frustum(camera_transform.column(3),
                                              screen.transform_,
                                              0.1, 100000.f));

        math::mat4 view_transform(screen.transform_);
        view_transform[12] = 0.f;
        view_transform[13] = 0.f;
        view_transform[14] = 0.f;
        view_transform[15] = 1.f;

        math::vec3 camera_position(camera_transform.column(3)[0],
                                   camera_transform.column(3)[1],
                                   camera_transform.column(3)[2]);

        view_transform = scm::math::make_translation(camera_position)
                         * view_transform;

        math::mat4 view_matrix(scm::math::inverse(view_transform));

        // update light data uniform block
        if (scene.lights_.size() > 0) {

            if (!light_information_) {
                light_information_ =
                new scm::gl::uniform_block<LightInformation>(ctx.render_device);
            }

            light_information_->begin_manipulation(ctx.render_context);

            LightInformation light;

            light.light_count = math::vec4i(scene.lights_.size(),
                                            scene.lights_.size(),
                                            scene.lights_.size(),
                                            scene.lights_.size());

            for (unsigned i(0); i < scene.lights_.size(); ++i) {

                math::mat4 transform(scene.lights_[i].transform_);

                // calc light radius and position
                light.position[i] = math::vec4(transform[12], transform[13],
                                               transform[14], transform[15]);
                float radius = scm::math::length(light.position[i] - transform
                                              * math::vec4(0.f, 0.f, 1.f, 1.f));

                light.color_radius[i] = math::vec4(scene.lights_[i].color_.r(),
                                                   scene.lights_[i].color_.g(),
                                                   scene.lights_[i].color_.b(),
                                                   radius);
            }

            **light_information_ = light;

            light_information_->end_manipulation();

            ctx.render_context->bind_uniform_buffer(
                                         light_information_->block_buffer(), 0);
        }

        for (auto& core: scene.nodes_) {

            auto geometry = GeometryBase::instance()->get(core.geometry_);
            auto material = MaterialBase::instance()->get(core.material_);

            if (material && geometry) {
                material->use(ctx);

                if (float_uniforms_.find(core.material_)
                    != float_uniforms_.end())  {

                    for (auto val : float_uniforms_[core.material_])
                        material->get_shader()->set_float(ctx, val.first,
                                                          val.second);
                }

                if (texture_uniforms_.find(core.material_)
                    != texture_uniforms_.end()) {

                    for (auto val : texture_uniforms_[core.material_])
                        material->get_shader()->set_sampler2D(ctx, val.first,
                                                              *val.second);
                }

                material->get_shader()->set_mat4(ctx, "projection_matrix",
                                                 projection);

                material->get_shader()->set_mat4(ctx, "view_matrix",
                                                 view_matrix);

                material->get_shader()->set_mat4(ctx, "model_matrix",
                                                 core.transform_);

                material->get_shader()->set_mat4(ctx, "normal_matrix",
                                          scm::math::transpose(
                                          scm::math::inverse(core.transform_)));

                geometry->draw(ctx);

                material->unuse(ctx);

            } else if (material) {
                WARNING("Cannot render geometry \"%s\": Undefined geometry "
                        "name!", core.geometry_.c_str());

            } else if (geometry) {
                WARNING("Cannot render geometry \"%s\": Undefined material "
                        "name: \"%s\"!", core.geometry_.c_str(),
                        core.material_.c_str());

            } else {
                WARNING("Cannot render geometry \"%s\": Undefined geometry "
                        "and material name: \"%s\"!", core.geometry_.c_str(),
                        core.material_.c_str());
            }
        }

        if (scene.lights_.size() > 0) {
            ctx.render_context->reset_uniform_buffers();
        }
    }

    fbo->unbind(ctx);

    // draw fps on the screen
    if (draw_fps) {
        if (!text_renderer_)
            text_renderer_ = new TextRenderer(pipeline_->get_context());

        if (mode == CENTER) {
            text_renderer_->render_fps(pipeline_->get_context(), center_eye_fbo_,
                                       pipeline_->get_application_fps(),
                                       pipeline_->get_rendering_fps());
        } else if (mode == LEFT) {
            text_renderer_->render_fps(pipeline_->get_context(), left_eye_fbo_,
                                       pipeline_->get_application_fps(),
                                       pipeline_->get_rendering_fps());
        } else {
            text_renderer_->render_fps(pipeline_->get_context(), right_eye_fbo_,
                                       pipeline_->get_application_fps(),
                                       pipeline_->get_rendering_fps());
        }
    }

    // return the buffer and set the already-rendered-flag
    if (mode == CENTER) {
        rendererd_center_eye_ = true;
        return center_eye_buffers_[name];
    } else if (mode == LEFT) {
        rendererd_left_eye_ = true;
        return left_eye_buffers_[name];
    } else {
        rendererd_right_eye_ = true;
        return right_eye_buffers_[name];
    }
}
예제 #10
0
void Shader::disable(void) { unuse(); }
예제 #11
0
int main_w2(int base_in) {

    //    use the input number to set the global variable
    
    _base_ = base_in;
    
    // see http://stackoverflow.com/questions/6792235/declaring-global-variable-array-inside-a-function-in-c
    
    // http://forum.codecall.net/topic/51010-dynamic-arrays-using-malloc-and-realloc/
    
    used_number = (int *)malloc(sizeof(int*) * _base_); // seems need (int *); should not be under c99
    
    if (used_number ==NULL) {
        printf("Error allocating memory!\n"); //print an error message
        return 1; //return with failure
    }
    
//    used_number[0] = 90; <-- remember to set it back to 0 if used
//    used_number[_base_ - 1] = 99;
//    test_used_number(0);
//    test_used_number(_base_ - 1);
//    used_number[0] = 0;
//    used_number[_base_ - 1] = 0;
    
    clock_t tick_l;
    
    int cnt_l = 0;
    int ab, cd, ef, gh;
    
    tick_l = clock();
    reset_w2();
    
    for (ab = START_WITH_2_ALWAYS * _base_; ab < (_base_ * _base_); ab++)
             // a cannot be 0 and 1, start from 20
        if (use(ab)) { //try to use ab
            for (cd = START_WITH_2_ALWAYS * _base_; cd < ab; cd++)
                // ab > cd to avoid ef < 0 and cd run into ab
                if (use(cd)) {
                    ef = ab - cd;    // you do not need to loop over ef and gh
                    gh = (1 * (_base_ * _base_ + _base_ + 1)) - ef;
                                     // a - b = c + d = p = 111
                                     // fixed a and b then c and d is fixed by logic
                    
                    if (use(ef)) {
                        if (use(gh)) {
                            if (cnt_l < MAX_SOL_TO_PRINT) {
                                printf("%d: %d - %d = %d, %d + %d = %d\n", cnt_l + 1, ab, cd, ef, ef, gh, (1 * (_base_ * _base_ + _base_ + 1)) );
                            }
                            cnt_l++; // need that for those time you cannot print all
                            unuse(gh);
                        }
                        unuse(ef);
                    }
                    unuse(cd);
                }
            unuse(ab); // if used(ab) unuse it
        }
    
    tick_l = clock()-tick_l;
    
    printf("\n_base_ is: %d\n", _base_);
    
    printf("time used: %f\n", ((double)tick_l)/CLOCKS_PER_SEC);
    // printf("MAX_SOL_TO_PRINT: %d\n\n", MAX_SOL_TO_PRINT);
    printf("number of solutions: %d\n\n", cnt_l);
    
    free(used_number);
    
    return 0;
}