void scr_repaint_all(void)
{
    CHECK_START();
    paint_all++;
    paint_request++; // TODO need atomic
    hal_sem_release( &paint_sem );
}
    bool ParseBoundingBox(Core::Buffer& buffer, Math::BoundingBox& value)
    {
		Parser* parser = GetDefaultParser();
        CHECK_START(buffer);
        Math::vec3 p[8];
		for (int i = 0; i < 8; ++i)
			parser->Parse(WORD_VEC3F, buffer, &p[i]);
        CHECK_END(buffer);
        return true;
    }
	bool ParseNaviMesh(Core::Buffer &buffer, void* object)
	{
		Attributes::INaviMesh* value = (Attributes::INaviMesh*)object;
		Parser* parser = GetDefaultParser();

		CHECK_START(buffer);
		Core::String name;
		while (1)
		{
			Core::String word = buffer.ReadWord();
			KeywordCode code = ParseKeyword(word);
			switch (code)
			{
			case WORD_CLOSE_BRACKET:
			{
				return true;
			}
			case WORD_WORLD_MATRIX:
			{
				Math::mat4 m;
				parser->Parse<Math::mat4>(WORD_MATRIX4X4F, buffer, m);
				value->SetTransform(m);
			}
				break;
			case WORD_VERTEX_POSITION:
			{
				Math::vec3v v;
				parser->Parse(WORD_VEC3FV, buffer, &v);
				value->SetVertexPositions(v.data(), (std::uint32_t)v.size());
			}
				break;
			case WORD_NORMALS:
			{
				Math::vec3v v;
				parser->Parse(WORD_VEC3FV, buffer, v);
				value->SetVertexNormals(v.data(), (std::uint32_t)v.size());
			}
				break;
			case WORD_FACES:
			{
				Math::ivec3v f;
				parser->Parse(WORD_VEC3IV, buffer, f);
				value->SetTriangles(f.data(), (std::uint32_t)f.size());
			}
				break;
			default:
				throw Error::LoaderException(L"Unexpected keyword " + word);
			}
		}
		return false;
	}
void w_request_async_repaint( rect_t *r )
{
    CHECK_START();

    rect_t old_total = total;
    int old_pq = paint_request;

    rect_add( &total, &old_total, r );

    // Other thread changed something, we have collision.
    // For now just repaint all the screen.
    if(old_pq != paint_request)
        paint_all++;

    paint_request++; // TODO need atomic
    hal_sem_release( &paint_sem );
}
	bool ParseMaterial(Core::Buffer& buffer, void* object)
	{
		Parser* parser = GetDefaultParser();
		Attributes::IMaterial* mat = (Attributes::IMaterial*)(object);

		CHECK_START(buffer);

		Core::String name;
		while (1)
		{
			Core::String word = buffer.ReadWord();
			KeywordCode code = ParseKeyword(word);
			switch (code)
			{
			case WORD_CLOSE_BRACKET:
				return true;
			case WORD_NAME:
			{
				Core::String value;
				parser->Parse(WORD_STRING, buffer, &value);
				mat->SetName(value);
			}
				break;
			case WORD_ALPHA:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetAlpha(value);
			}
				break;
			case WORD_AMBIENT:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, value);
				mat->SetAmbient(value);
			}
				break;
			case WORD_DARKNESS:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetDarkness(value);
			}
				break;
			case WORD_DIFFUSE_COLOR:
			{
				Math::vec3 value;
				parser->Parse(WORD_VEC3F, buffer, &value);
				mat->SetDiffuseColor(Math::vec4(value, mat->GetAlpha()));
			}
				break;
			case WORD_DIFFUSE_FRESNEL:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetDiffuseFresnel(value);
			}
				break;
			case WORD_DIFFUSE_FRESNEL_FACTOR:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetDiffuseFresnelFactor(value);
			}
				break;
			case WORD_DIFFUSE_INTENSITY:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetDiffuseIntensity(value);
			}
				break;
			case WORD_EMIT:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetEmit(value);
			}
				break;
			case WORD_MIRROR_COLOR:
			{
				Math::vec3 value;
				parser->Parse(WORD_VEC3F, buffer, &value);
				mat->SetMirrorColor(value);
			}
				break;
			case WORD_ROUGHNESS:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetRoughness(value);
			}
				break;
			case WORD_SPECULAR_ALPHA:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetSpecularAlpha(value);
			}
				break;
			case WORD_SPECULAR_COLOR:
			{
				Math::vec3 value;
				parser->Parse(WORD_VEC3F, buffer, &value);
				mat->SetSpecularColor(Math::vec4(value, mat->GetSpecularAlpha()));
			}
				break;
			case WORD_SPECULAR_HARDNESS:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetSpecularFactor(value);
			}
				break;
			case WORD_SPECULAR_INTENSITY:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetSpecularIntensity(value);
			}
				break;
			case WORD_SPECULAR_IOR:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetSpecularIndexOfRefraction(value);
			}
				break;
			case WORD_SPECULAR_SLOPE:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetSpecularSlope(value);
			}
				break;
			case WORD_TRANSLUCENCY:
			{
				float value;
				parser->Parse(WORD_FLOAT, buffer, &value);
				mat->SetTranslucency(value);
			}
				break;
			case WORD_DIFFUSE_TEXTURE_SLOT:
			{
                auto slot = System::CreateInstancePtr<Attributes::IDiffuseTextureSlot>(
					Attributes::CLSID_TextureSlot, Attributes::IID_IDiffuseTextureSlot);
                parser->Parse(WORD_DIFFUSE_TEXTURE_SLOT, buffer, slot.get());
                mat->SetDiffuseTextureSlot(slot);
			}
				break;
			case WORD_NORMAL_TEXTURE_SLOT:
			{
				auto slot = System::CreateInstancePtr<Attributes::INormalTextureSlot>(
					Attributes::CLSID_TextureSlot, Attributes::IID_INormalTextureSlot);
                parser->Parse(WORD_NORMAL_TEXTURE_SLOT, buffer, slot.get());
                mat->SetNormalTextureSlot(slot);
			}
				break;
			case WORD_SPECULAR_TEXTURE_SLOT:
			{
				auto slot = System::CreateInstancePtr<Attributes::ISpecularIntensityTextureSlot>(
					Attributes::CLSID_TextureSlot, Attributes::IID_ISpecularIntensityTextureSlot);

                parser->Parse(WORD_SPECULAR_TEXTURE_SLOT, buffer, slot.get());
                mat->SetSpecularTextureSlot(slot);
			}
				break;
			default:
				throw Error::LoaderException(L"Unexpected keyword " + word);
			}
		}
		return false;
	}
	PUNK_ENGINE_LOCAL bool ParseTransform(Core::Buffer &buffer, void* object) {

		Attributes::ITransform* transform = (Attributes::ITransform*)object;
		Parser* parser = GetDefaultParser();

		CHECK_START(buffer);
		while (1)
		{
			if (buffer.IsEnd())
				throw Error::LoaderException(L"Can't parse object");

			Core::String word = buffer.ReadWord();

			KeywordCode code = ParseKeyword(word);
			switch (code)
			{
			case WORD_CLOSE_BRACKET:
				return true;
			case WORD_LOCATION:
			{
				Math::vec3 value;
				parser->Parse<Math::vec3>(WORD_VEC3F, buffer, value);
				transform->SetPosition(value);
			}
				break;
			case WORD_ROTATION:
			{
				Math::quat value;
				parser->Parse<Math::quat>(WORD_QUAT, buffer, value);
				transform->SetRotation(value);
			}
				break;
			case WORD_SCALE:
			{
				Math::vec3 value;
				parser->Parse<Math::vec3>(WORD_VEC3F, buffer, value);
				transform->SetScale(value);
			}
				break;
			case WORD_ENTITY_NAME:
			{
				Core::String value;
				parser->Parse<Core::String>(WORD_STRING, buffer, value);
			}
				break;
			case WORD_BOUNDING_BOX:
			{
			}
				break;
			case WORD_ACTION_REF:
			{
				Core::String name;
				parser->Parse<Core::String>(WORD_STRING, buffer, name);
				Attributes::IAnimated* animated = nullptr;
				transform->QueryInterface(Attributes::IID_IAnimated, (void**)&animated);                
				if (animated) {
					animated->AddAnimation(name);
					animated->Release();
				}
			}
				break;
			default:
				throw Error::LoaderException(L"Unexpected keyword " + word);
			}
		}
	}