void GetSFieldHandle<SFAttachmentPtrMap>::flatten(MapList &vList) { vList.clear(); SFAttachmentPtrMap const *pMap = static_cast<SFAttachmentPtrMap const *>(_pField); if(pMap != NULL) { AttachmentMap::const_iterator mapIt = pMap->getValue().begin(); AttachmentMap::const_iterator mapEnd = pMap->getValue().end (); for(; mapIt != mapEnd; ++mapIt) { if(mapIt->second->getInternal() == true) continue; std::string szKey; TypeTraits<UInt32>::putToString((mapIt->first & 0x0000FFFF), szKey); ListEntry tmpEntry; tmpEntry.first.push_back(szKey); tmpEntry.second = mapIt->second; vList.push_back(tmpEntry); } } }
void DynamicMaterial::setTextures(MaterialEditor* src) { if(!m_material) return; if(m_stream) m_stream->build(); // Textures m_material->setTexture("diffuseArray", src->getDiffuseArray()); m_material->setTexture("normalArray", src->getNormalArray()); if(m_stream) { m_stream->setTexture("diffuseArray", src->getDiffuseArray()); m_stream->setTexture("normalArray", src->getNormalArray()); printf("Textures set\n"); } // Bind all the maps typedef std::set<const char*> MapList; MapList maps; for(size_t i=0; i<m_layers.size(); ++i) { if(m_layers[i]->map && m_layers[i]->map[0]) maps.insert( m_layers[i]->map ); if(m_layers[i]->map2 && m_layers[i]->map2[0]) maps.insert( m_layers[i]->map2 ); update(i); } for(MapList::iterator i=maps.begin(); i!=maps.end(); ++i) { EditableTexture* map = src->getMap(*i); if(map) { m_material->setTexture(*i, map->getTexture()); if(m_stream) { if(map->getTextureStream()) m_stream->addStream(*i, map->getTextureStream()); else m_stream->setOverlayTexture(*i, map->getTexture()); } } } }
// Изменение иконки пользователя. void OnUserSexChanged(BYTE *InBuffer) { String name; DWORD sex; try { //name GetStreamString(&InBuffer, &name); //ip GetStreamString(&InBuffer, NULL); //male GetStreamDword(&InBuffer, NULL); //new male GetStreamDword(&InBuffer, &sex); UpdateOnlineUserSex(name, sex); MapList params; params.insert(pair<String, String>("user", name)); params.insert(pair<String, String>("sex", sex)); String json_object = SetParametersObject(params); SendNotification("user_sex_changed", json_object, GetConnectionsRef(true)); } catch (Exception *E) { throw(Format(e_user_sex_changed, ARRAYOFCONST((E->Message)))); } }
void GetSFieldHandle<SFChunkBlockPtrMap>::flatten(MapList &vList) { vList.clear(); SFChunkBlockPtrMap const *pMap = static_cast<SFChunkBlockPtrMap const *>(_pField); if(pMap != NULL) { ChunkBlockMap::const_iterator mapIt = pMap->getValue().begin(); ChunkBlockMap::const_iterator mapEnd = pMap->getValue().end (); for(; mapIt != mapEnd; ++mapIt) { ListEntry tmpEntry; KeyPool::the()->keyToStringList(mapIt->first, tmpEntry.first); tmpEntry.second = mapIt->second; vList.push_back(tmpEntry); } } }
// Отключение от канала стороннего или виртуального пользователя. void OnUserChannelDisconnect(BYTE *InBuffer) { String bot, channel, name; try { // virtual user. GetStreamString(&InBuffer, &bot); // channel. GetStreamString(&InBuffer, &channel); if (UserIsMonitoring(bot, channel)) { // name. GetStreamString(&InBuffer, &name); MapList params; params.insert(pair<String, String>("user", name)); params.insert(pair<String, String>("channel", channel)); String json_object = SetParametersObject(params); SendNotification("user_channel_disconnect", json_object, GetChannelConnections(channel)); DeleteUserChannel(name, channel); // If channel watcher was disconnected, then find new watcher. if (name == bot) { ChangeChannelWatcher(channel); } } } catch (Exception *E) { throw(Format(e_user_channel_disconnect, ARRAYOFCONST((E->Message)))); } }
// Выход из чата. void OnUserDisconnect(BYTE *InBuffer) { String name; try { //name GetStreamString(&InBuffer, &name); RemoveUserFromChannels(name); // Проверяем, является ли пользователь виртуальным. Если да, то проверяем список отслеживаний каналов. LogicalConnections::iterator connection = FindConnectionByUser(name); if (ConnectionExists(connection)) { UnsetConnectionUser(connection); } RemoveOnlineUser(name); MapList params; params.insert(pair<String, String>("user", name)); String json_object = SetParametersObject(params); SendNotification("user_disconnect", json_object, GetConnectionsRef(true)); } catch (Exception *E) { throw(Format(e_user_disconnect, ARRAYOFCONST((E->Message)))); } }
// Подключение к каналу стороннего пользователя. void OnUserChannelConnect(BYTE *InBuffer) { String bot, name, channel, ip, query; DWORD male; try { //virtual user GetStreamString (&InBuffer, &bot); //channel GetStreamString(&InBuffer, &channel); // If this user is channel watcher. if (UserIsMonitoring(bot, channel)) { //name GetStreamString(&InBuffer, &name); //ip GetStreamString(&InBuffer, &ip); //male GetStreamDword(&InBuffer, &male); AddUserChannel(name, channel); MapList params; params.insert(pair<String, String>("user", name)); params.insert(pair<String, String>("channel", channel)); String json_object = SetParametersObject(params); SendNotification("user_channel_connect", json_object, GetChannelConnections(channel)); } } catch (Exception *E) { throw(Format(e_user_channel_connect, ARRAYOFCONST((E->Message)))); } }
// Set value from the map list. String SetParametersObject(MapList params, bool last_param_array) { MapList::iterator it; MapList::iterator last_param = params.end(); last_param--; String params_object = ""; for (it = params.begin(); it != params.end(); it++) { AddPair(params_object, it->first, it->second, (last_param == it && last_param_array) ? false : true, (last_param != it) ? true : false); } return params_object; }
BattleArea::BattleArea(Map *map){ setItemIndexMethod(QGraphicsScene::NoIndex); /// QTimer *timer = new QTimer(); timer->setInterval(1000); m_width = m_height = map->size() * SIZE; setSceneRect(0, 0, m_width, m_height); BotPack *bpack = new BotPack("data/robots/botpacks/tank-0.bpack"); // must be dynamic, too (maybe by reference) MapList *mapList = map->mapList(); int mapSize = map->size(); int i, j; int listpos = 0; // the TileObject used as BattleArea "background" TileObject *tile = new TileObject("data/textures/" + map->pathTexture() + ".svgz", map->pathColor(), map->pathAltColor()); setBackgroundBrush(tile->pixmap()); // must add on KWB::Map a method to load the map for (i = 0; i < mapSize; i++){ for (j = 0; j < mapSize; j++){ listpos = (j * mapSize) + i; // iteratte trough the map list (objects and items) if (mapList->at(listpos) == Ammo){ AmmoItem *ammo = new AmmoItem("data/items/" + map->ammoTexture() + ".svgz", QPoint(i, j), map->ammoValue()); addItem(ammo); } else if (mapList->at(listpos) == Block){ BlockObject *block = new BlockObject("data/textures/" + map->blockTexture() + ".svgz", QPoint(i, j), map->blockColor()); addItem(block); } else if (mapList->at(listpos) == Enemy){ // TODO } else if (mapList->at(listpos) == Energy){ EnergyItem *energy = new EnergyItem("data/items/" + map->energyTexture() + ".svgz", QPoint(i, j), map->energyValue()); addItem(energy); } else if (mapList->at(listpos) == StartPoint){ // the user programmed Robot m_robot = new Robot(bpack, this, QPoint(i, j)); addItem(m_robot->robotObject()); } else if (mapList->at(listpos) == Wall){ WallObject *wall = new WallObject("data/textures/" + map->wallTexture() + ".svgz", QPoint(i, j), map->wallColor()); addItem(wall); connect(wall, SIGNAL(deleteMe(QGraphicsItem*)), this, SLOT(deleteItem(QGraphicsItem*))); } else if (mapList->at(listpos) == Water){ WaterObject *water = new WaterObject("data/textures/" + map->waterTexture() + ".svgz", QPoint(i, j), timer); addItem(water); } else if (mapList->at(listpos) == Weapon){ WeaponItem *weapon = new WeaponItem("data/items/" + map->weaponTexture() + ".svgz", QPoint(i, j), map->weaponValue()); addItem(weapon); } }
void ForEachTime(unsigned item_index, C &&c) { assert(item_index < maps.size()); const auto &mi = maps[item_index]; for (unsigned i = 0; i < MAX_WEATHER_TIMES; ++i) if (mi.times[i]) c(IndexToTime(i)); }
// Подключение к каналу виртуального пользователя. void OnVirtualUserChannelConnect(BYTE *InBuffer) { String name, channel_name; try { // virtual user. GetStreamString (&InBuffer, &name); // channel. GetStreamString(&InBuffer, &channel_name); // topic. GetStreamString(&InBuffer, NULL); // greeting. GetStreamString(&InBuffer, NULL); LogicalConnections::iterator connection = FindConnectionByUser(name); OnlineUsersList::iterator user = GetConnectionUser(connection); ChannelsList::iterator channel = FindChannelByName(channel_name); StringList channel_users; if (!IsChannelMonitored(channel_name)) { AddChannelWatcher(name, channel_name); Channel channel_info = GetChannelInfo(channel_name); channel_users = GetChannelUsersList(name, channel_name); channel_info.online_users = channel_users.size(); UpdateChannel(channel, GetChannelInfo(channel_name)); for (unsigned int i = 0; i < channel_info.online_users; i++) { AddUserChannel(name, channel_name); } } else { AddUserChannel(name, channel_name); channel_users = GetChannelUsers(channel_name); } MapList params; params.insert(pair<String, String>("channel", channel_name)); params.insert(pair<String, String>("topic", channel->topic)); params.insert(pair<String, String>("greeting", channel->greeting)); params.insert(pair<String, String>("users", "[" + implode(channel_users) + "]")); String json_object = SetParametersObject(params, true); SendNotification("virtual_user_channel_connect", json_object, connection, false); } catch (Exception *E) { throw(Format(e_virtual_user_channel_connect, ARRAYOFCONST((E->Message)))); } }
// Вход в чат. void OnUserConnect(BYTE *InBuffer) { String name, ip, query; DWORD male; try { //name GetStreamString(&InBuffer, &name); //ip GetStreamString(&InBuffer, &ip); //male GetStreamDword(&InBuffer, &male); // Get user from registred users list, add it's reference to online users and update user info. UsersList::iterator user = FindUserByName(name); CFUserInfo user_info = GetUserInfo(name); OnlineUsersList::iterator online_user = AddOnlineUser(user, user_info.state, user_info.client_version, user_info.process, user_info.window_activity, user_info.downtime); UpdateUser(user, user_info.computer_id, user_info.ip, user_info.male); // If user is in authorization queue. AuthQueueMap::iterator auth_queue_item = FindAuthQueueByUser(name); if (IsAuthQueueElement(auth_queue_item)) { LogicalConnections::iterator connection = GetAuthQueueConnection(auth_queue_item); SetConnectionUser(connection, online_user); SetAuthorizationStatus(connection, 9); DeleteAuthQueueItem(auth_queue_item); } MapList params; params.insert(pair<String, String>("name", name)); params.insert(pair<String, String>("ip", ip)); params.insert(pair<String, String>("sex", male)); String json_object = SetParametersObject(params, true); SendNotification("user_connect", json_object, GetConnectionsRef(true)); } catch (Exception *E) { throw(Format(e_user_connect, ARRAYOFCONST((E->Message)))); } }
// Изменение темы. void OnChannelTopicChanged(BYTE *InBuffer) { String bot, name, channel, topic; try { //bot_prop.name GetStreamString(&InBuffer, &bot); // Если виртуальный пользователь является пользователем, отслеживающим данный канал. if (UserIsMonitoring(bot, channel)) { //channel GetStreamString(&InBuffer, &channel); //name GetStreamString(&InBuffer, &name); //ip GetStreamString(&InBuffer, NULL); //male GetStreamDword(&InBuffer, NULL); //new theme GetStreamString(&InBuffer, &topic); int timestamp = time(NULL); UpdateChannelTopic(channel, topic, name, timestamp); MapList params; params.insert(pair<String, String>("channel", channel)); params.insert(pair<String, String>("topic_editor", name)); params.insert(pair<String, String>("topic", topic)); params.insert(pair<String, String>("timestamp", timestamp)); String json_object = SetParametersObject(params); SendNotification("channel_topic_changed", json_object, GetChannelConnections(channel)); } } catch (Exception *E) { throw(Format(e_chnl_theme_changed, ARRAYOFCONST((E->Message)))); } }
void CLxVertexMapSelection::GetList ( MapList &list) { LXtScanInfoID scan; MapInfo info; const char *str; void *pkt; scan = 0; while (scan = srv_sel.ScanLoop (scan, sel_ID, &pkt)) { pkt_trans.Type (pkt, &info.type); if (!Include (info.type)) continue; pkt_trans.Name (pkt, &str); info.name = str; list.push_back (info); } }
// Публикация в общий канал. void OnPublicChannelMessage(BYTE *InBuffer) { String bot, name, channel, text; DWORD mode, male, image_length; try { //bot nick GetStreamString (&InBuffer, &bot); //nick GetStreamString(&InBuffer, &name); //ip GetStreamString(&InBuffer, NULL); //male GetStreamDword(&InBuffer, &male); //channel GetStreamString(&InBuffer, &channel); // Если виртуальный пользователь является пользователем, отслеживающим данный канал. if (UserIsMonitoring(bot, channel)) { //rezim GetStreamDword(&InBuffer, &mode); //text GetStreamString(&InBuffer, &text); GetStreamDword(&InBuffer, &image_length); MapList params; params.insert(pair<String, String>("sender", name)); params.insert(pair<String, String>("channel", channel)); params.insert(pair<String, String>("mode", mode)); params.insert(pair<String, String>("message", text)); if (image_length > 0) { String image_name = SaveData(InBuffer, image_length); if (!image_name.IsEmpty()) { params.insert(pair<String, String>("image", image_name)); } } String json_object = SetParametersObject(params); SendNotification("public_mess", json_object, GetChannelConnections(channel)); } } catch (Exception *E) { throw(Format(e_user_mess_recieve, ARRAYOFCONST((E->Message)))); } }
ButtonAction TouchKeyboard::handle_button_pressed( TextButton* text_button ) { if( this->keys.find(text_button) != this->keys.end() ) { std::string button_text = this->handle_key_pressed( text_button->text ); // FIXME: besser db-patterns abfragen! if( this->current_layout_dead_keys.find(button_text)!=std::string::npos ) { this->modifier = button_text; } else if( button_text == "<" ) { if( this->modifier.length() ) { this->modifier = ""; } else if( this->written_chars.size() ) { this->written_chars.pop_back(); this->handle_text_changed(); } } else { if( this->modifier.length() ) { button_text = this->modifier + button_text; if( db ) { int rc; button_text = replace_pattern( button_text, "'", "\'" ); std::string stmt = "select result from modifiers where pattern='"+button_text+"'"; MapList result; if( (rc = sqlite3_exec(db, stmt.c_str(), map_list_callback, &result, 0))!=SQLITE_OK ) { std::stringstream msg; msg << sqlite3_errmsg(db) << " (" << rc << "), in statement: " << stmt; throw ERROR( msg.str() ); } for( MapList::iterator ri=result.begin(); ri!=result.end(); ri++ ) { button_text = (*ri)["result"]; break; } } } utf8_to_utf8_char_list( (const unsigned char*)button_text.c_str(), this->written_chars ); this->modifier = ""; this->handle_text_changed(); } return BUTTON_ACTION_PRESSED | BUTTON_ACTION_SCREEN_SUB; } else if( text_button == &this->layout_minus ) { if( this->current_layout != this->layouts.begin() ) { this->current_layout--; } else if( this->layouts.end() != this->layouts.begin() ) { this->current_layout = this->layouts.end(); this->current_layout--; } this->init_button_vram(); this->program.config->set( "touch_keyboard.current_layout", *this->current_layout ); // WARNING: button release handler will crash because of iterator invalidation if STOP_HANDLER ist not set: return BUTTON_ACTION_PRESSED | BUTTON_ACTION_SCREEN_SUB | BUTTON_ACTION_STOP_HANDLER; } else if( text_button == &this->layout_plus ) { if( this->layouts.size() && &*this->current_layout != &*this->layouts.rbegin() ) { this->current_layout++; } else { this->current_layout = this->layouts.begin(); } this->init_button_vram(); this->program.config->set( "touch_keyboard.current_layout", *this->current_layout ); // WARNING: button release handler will crash because of iterator invalidation when STOP_HANDLER ist not set: return BUTTON_ACTION_PRESSED | BUTTON_ACTION_SCREEN_SUB | BUTTON_ACTION_STOP_HANDLER; } return this->ButtonProvider::handle_button_pressed( text_button ); }
gcc_const unsigned GetItemCount() const { return maps.size(); }
bool IsTimeAvailable(unsigned item_index, unsigned time_index) const { assert(item_index < maps.size()); assert(time_index < MAX_WEATHER_TIMES); return maps[item_index].times[time_index]; }
void TouchKeyboard::reload_current_layout() { this->free_button_vram(); for( TextButtonSetStorage::iterator ki=this->keys.begin(); ki!=this->keys.end(); ki++ ) { if( *ki ) { delete *ki; } } this->keys.clear(); this->text_buttons.clear(); this->text_buttons.push_back( &this->reference_key ); this->text_buttons.push_back( &this->layout_minus ); this->text_buttons.push_back( &this->layout_label ); this->text_buttons.push_back( &this->layout_plus ); this->close_db(); if( this->current_layout != this->layouts.end() ) { int rc; int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX; if( (rc = sqlite3_open_v2( this->current_layout->c_str(), &db, flags, 0))!=SQLITE_OK ) { std::stringstream msg; msg << sqlite3_errmsg(db) << ": " << rc << " (" << *this->current_layout << ")"; this->close_db(); throw ERROR( msg.str() ); } std::string stmt = "select key, value from settings"; MapList result; if( (rc = sqlite3_exec(db, stmt.c_str(), map_list_callback, &result, 0))!=SQLITE_OK ) { std::stringstream msg; msg << sqlite3_errmsg(db) << " (" << rc << "), in statement: " << stmt; throw ERROR( msg.str() ); } for( MapList::iterator ri=result.begin(); ri!=result.end(); ri++ ) { if( (*ri)["key"]=="description" ) this->current_layout_description = (*ri)["value"]; if( (*ri)["key"]=="language" ) this->current_layout_language = (*ri)["value"]; if( (*ri)["key"]=="keys" ) this->current_layout_keys = (*ri)["value"]; if( (*ri)["key"]=="dead_keys" ) this->current_layout_dead_keys = (*ri)["value"]; } } this->layout_label.text = this->current_layout_language; StringList keyboard_characters; utf8_to_utf8_char_list( (const unsigned char*)this->current_layout_keys.c_str(), keyboard_characters ); int key_x_start = 1; int key_x_offset = this->reference_key.sensor_width+1; int key_x = key_x_start; int key_y_start = 50; int key_y_offset = this->reference_key.sensor_height+1; int key_y = key_y_start; for( StringList::iterator kci = keyboard_characters.begin(); kci != keyboard_characters.end(); kci++ ) { if( *kci=="\n" ) { key_x = key_x_start; key_y += key_y_offset; continue; } if( *kci=="\t" ) { key_x += key_x_offset / 2; continue; } TextButton* new_key = new TextButton( this->reference_key ); new_key->hidden = false; new_key->owns_bg_vram = false; new_key->owns_text_vram = true; new_key->text = *kci; if( new_key->text == "ˇ" ) { new_key->text_y_offset += 3; } else if( new_key->text == "¯" || new_key->text == "´" || new_key->text == "`" ) { new_key->text_y_offset += 3; new_key->font_size += 2; } new_key->x = key_x; new_key->y = key_y; this->text_buttons.push_back( new_key ); this->keys.insert( new_key ); key_x += key_x_offset; } }
bool DynamicMaterial::compile() { std::string source; // Inputs source += "#version 130\n\n" "in vec3 worldNormal;\n" "in vec3 worldPos;\n\n" "uniform vec3 lightDirection;\n\n"; // Samplers source += "uniform sampler2DArray diffuseArray;\n" "uniform sampler2DArray normalArray;\n"; // Maps typedef std::set<std::string> MapList; MapList maps; for(size_t i=0; i<m_layers.size(); ++i) { if(m_layers[i]->map && m_layers[i]->map[0]) maps.insert( str(m_layers[i]->map) ); if(m_layers[i]->map2 && m_layers[i]->map2[0]) maps.insert( str(m_layers[i]->map2) ); } for(MapList::iterator i=maps.begin(); i!=maps.end(); ++i) source += "uniform sampler2D " + *i + "Map;\n"; for(MapList::iterator i=maps.begin(); i!=maps.end(); ++i) source += "uniform vec4 " + *i + "Info;\n"; source += "\n\n"; // Variables for(size_t i=0; i<m_layers.size(); ++i) { std::string index = str(i); if(m_layers[i]->projection == PROJECTION_FLAT) source += "uniform vec2 scale" + index + ";\n"; else source += "uniform vec3 scale" + index + ";\n"; source += "uniform float opacity" + index + ";\n"; if(m_layers[i]->type == LAYER_AUTO) source += "uniform vec3 autoMin" + index + ";\n" "uniform vec3 autoMax" + index + ";\n" "uniform vec3 autoBlend" + index + ";\n"; } source += "\n\n//Utility functions\n"; // Functions source += "vec4 sampleTriplanar(float map, vec3 coord, vec3 weights) {\n" " vec4 c = vec4(coord.xyz, map);\n" " return texture(diffuseArray, c.yzw)*weights.xxxx + texture(diffuseArray, c.zxw)*weights.yyyy + texture(diffuseArray, c.xyw)*weights.zzzz;\n" "}\n"; source += "vec4 sampleTriplanerNormal(float map, vec3 coord, vec3 normal, vec3 weights) {\n" " vec4 c = vec4(coord.xyz, map);\n" " vec4 nX = texture(normalArray, c.yzw);\n" " vec4 nY = texture(normalArray, c.zxw);\n" " vec4 nZ = texture(normalArray, c.xyw);\n" " nX.xyz = nX.xyz * 2.0 - 1.0;\n" " nY.xyz = nY.xyz * 2.0 - 1.0;\n" " nZ.xyz = nZ.xyz * 2.0 - 1.0;\n" " if(dot(nX.xyz, normal)<0.0) nX.x = -nX.x;\n" " if(dot(nY.xyz, normal)<0.0) nY.y = -nY.y;\n" " if(dot(nZ.xyz, normal)<0.0) nZ.z = -nZ.z;\n" " vec3 result = normalize(nX.xyz*weights.xxx + nY.xyz*weights.yyy + nZ.xyz*weights.zzz);\n" " return vec4(result, nX.w*weights.x + nY.w*weights.y + nZ.w*weights.z);\n" "}\n"; source += "float getAutoWeight(vec3 value, vec3 vmin, vec3 vmax, vec3 vblend) {\n" // " vec3 ctr = (vmin + vmax) * 0.5;\n" // " vec3 r = smoothstep(ctr - vmin, ctr - vmin + vblend, abs(value - ctr));\n" " vec3 r = smoothstep(vmin-vblend, vmin, value) * smoothstep(vmax+vblend, vmax, value);\n" " return r.x * r.y * r.z;\n" "}\n"; source += "vec4 sampleMap(sampler2D map, vec4 info, vec2 coord) {\n" " coord = (coord - info.xy) * info.zw;\n" " return texture(map, coord);\n" "}\n"; source += "vec4 sampleDiffuse(float map, vec2 coord) {\n" " return texture(diffuseArray, vec3(coord, map));\n" "}\n"; source += "vec4 sampleNormal(float map, vec2 coord) {\n" " vec4 n = texture(diffuseArray, vec3(coord, map));\n" " return vec4(n.xyz * 2.0 - 1.0, n.w);\n" "}\n\n\n"; // Main function source += "// Main shader function\n" "void main() {\n" " vec4 diffuse = vec4(1,1,1,1);\n" " vec4 normal = vec4(0,1,0,0);\n" " float gloss = 0.0;\n" " float height;\n" " float weight;\n" " vec4 diff, norm;\n" " vec3 triplanar = max( (abs(worldNormal) - 0.2) * 0.7, 0.0);\n" " triplanar /= dot(triplanar, vec3(1,1,1));\n" " vec3 autoValue = vec3(worldPos.y, 1.0 - worldNormal.y, 0.0);\n" " \n"; // Vertical projection data source += " vec3 vertical = vec3(triplanar.x, 0, triplanar.z);\n" " vertical /= triplanar.y>0.99? 1: dot(vertical, vec3(1,1,1));\n\n"; // Sample maps if(!maps.empty()) { source += " // Sample maps\n"; for(MapList::iterator i=maps.begin(); i!=maps.end(); ++i) { source += " vec4 " + *i + "Sample = sampleMap(" + *i + "Map, " + *i + "Info, worldPos.xz);\n"; } source += "\n"; } // Apply layers const std::string rgba[] = { "r", "g", "b", "a" }; for(size_t i=0; i<m_layers.size(); ++i) { std::string index = str(i); MaterialLayer* layer = m_layers[i]; Colour colour(layer->colour); bool valid = true; source += " // Layer " + str(layer->name) + "\n"; switch(layer->type) { case LAYER_AUTO: source += " weight = getAutoWeight(autoValue, autoMin"+index+", autoMax"+index+", autoBlend"+index+");\n"; break; case LAYER_WEIGHT: if(!layer->map || !layer->map[0]) valid = false; else if(layer->mapData<4) source += " weight = " + str(layer->map) + "Sample." + rgba[layer->mapData] + ";\n"; else source += " weight = 1.0 - dot(" + str(layer->map) + "Sample, vec4(1,1,1,1));\n"; break; case LAYER_COLOUR: if(!layer->map || !layer->map[0]) valid = false; else source += " diff = " + str(layer->map) + "Sample;\n weight = 1.0;\n"; break; case LAYER_INDEXED: // ToDo this one break; } if(!valid) { printf("Error: Layer %s references an invalid map\n", (const char*)layer->name); continue; } // Sample textures if(layer->type != LAYER_COLOUR) { if(layer->texture < 0) source += " diff = vec4(" + str(colour.r) + ", " + str(colour.g) + ", " + str(colour.b) + ", 0);\n" " norm = vec4(0, 0, 1, 0);\n"; else if(layer->projection == PROJECTION_VERTICAL) source += " diff = sampleTriplanar("+str(layer->texture)+".0, worldPos * scale"+index+", vertical);\n" " norm = sampleTriplanerNormal("+str(layer->texture)+".0, worldPos * scale"+index+", worldNormal, vertical);\n"; else if(layer->projection == PROJECTION_TRIPLANAR) source += " diff = sampleTriplanar("+str(layer->texture)+".0, worldPos * scale"+index+", triplanar);\n" " norm = sampleTriplanerNormal("+str(layer->texture)+".0, worldPos * scale"+index+", worldNormal, triplanar);\n"; else source += " diff = sampleDiffuse("+str(layer->texture)+".0, worldPos.xz * scale"+index+");\n" " norm = sampleNormal("+str(layer->texture)+".0, worldPos.xz * scale"+index+");\n"; } // Blending switch(layer->blend) { case BLEND_NORMAL: case BLEND_HEIGHT: source += " diffuse = mix(diffuse, diff, weight * opacity" + index + ");\n" " normal = mix(normal, norm, weight * opacity" + index + ");\n"; break; case BLEND_MULTIPLY: source += " diffuse *= mix(vec4(1,1,1,1), diff, weight * opacity" + index + ");\n"; break; case BLEND_ADD: source += " diffuse += diff * weight * opacity" + index + ";\n"; break; } source += "\n"; } // Lighting (basic diffuse); source += " // Lighting\n"; source += " gl_FragColor = diffuse * 0.1 + diffuse * 0.9 * dot(worldNormal, lightDirection);\n"; source += " gl_FragColor = vec4(diffuse.rgb, 1);\n"; source += "}\n"; // Vertex shader - todo: add concavity attribute static const char* vertexShader = "varying vec3 worldNormal;\n" "varying vec3 worldPos;\n" "void main() {\n" " gl_Position = ftransform();\n" " worldPos = gl_Vertex.xyz;\n" " worldNormal = gl_Normal;\n" "}\n"; // Compile shader const char* fragmentShader = source.c_str(); VertexShader vert = Shader::createVertex(&vertexShader); FragmentShader frag = Shader::createFragment(&fragmentShader); Shader shader = Shader::link(vert, frag); // Setup material if(!m_material) m_material = new Material(); m_material->setShader(shader); // Streamed material if(m_streaming) { if(!m_stream) m_stream = new MaterialStream(m_material); m_stream->updateShader(); } // Initialise variables for(size_t i=0; i<m_layers.size(); ++i) { update(i); } // DEBUG: save generated shader FILE* fp = fopen("shader.glsl", "w"); if(fp) fwrite(source.c_str(), 1, source.length(), fp); if(fp) fclose(fp); printf("Compiled shader\n"); m_needsCompile = false; return false; }