/* * Copyright 2022 Frederico de Oliveira Linhares * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "texture.h" #include "color.h" #include "core.h" #include "font.h" #include "palette.h" #include "pgm_image.h" #include "point.h" void cg_free_texture(mrb_state *mrb, void* obj) { struct cg_texture *ptr = obj; SDL_DestroyTexture(ptr->data); mrb_free(mrb, ptr); } const struct mrb_data_type cg_texture_type = { "CG_Texture", cg_free_texture }; static mrb_value texture_alloc(mrb_state *mrb, mrb_value class) { struct RClass *cg_cTexture = mrb_class_ptr(class); enum mrb_vtype ttype = MRB_INSTANCE_TT(cg_cTexture); // I do not know if I need this. If things break, try uncomment this line. // if (ttype == 0) ttype = MRB_TT_OBJECT; return mrb_obj_value( (struct RObject*)mrb_obj_alloc(mrb, ttype, cg_cTexture)); } static mrb_value cg_cTexture_from_image(mrb_state *mrb, mrb_value self) { PGMImage pgm_img; struct mrb_value texture = texture_alloc(mrb, self); const char *file_path; struct cg_palette *palette; struct cg_texture *ptr; mrb_bool palette_given; SDL_Surface *surface = NULL; mrb_get_args( mrb, "z|d?", &file_path, &palette, &cg_palette_type, &palette_given); ptr = (struct cg_texture *)DATA_PTR(texture); if(ptr) mrb_free(mrb, ptr); ptr = (struct cg_texture *)mrb_malloc(mrb, sizeof(struct cg_texture)); if(palette_given) { if(!PGMImage_constructor(&pgm_img, file_path)) mrb_raise(mrb, E_RUNTIME_ERROR, pgm_img.error); // Depth = 8 bits image. // Pitch = 1 byte (8 bits) * image width. surface = SDL_CreateRGBSurfaceWithFormatFrom( pgm_img.data, pgm_img.width, pgm_img.height, 8, pgm_img.width, SDL_PIXELFORMAT_INDEX8); if(!surface) mrb_raise(mrb, E_RUNTIME_ERROR, SDL_GetError()); SDL_SetPaletteColors(surface->format->palette, palette->colors, 0, 256); } else { surface = IMG_Load(file_path); if(!surface) mrb_raise(mrb, E_RUNTIME_ERROR, IMG_GetError()); } ptr->data = SDL_CreateTextureFromSurface(cg_core.renderer, surface); SDL_SetTextureBlendMode(ptr->data, SDL_BLENDMODE_BLEND); SDL_FreeSurface(surface); if(palette_given) PGMImage_destructor(&pgm_img); if(ptr->data == NULL) mrb_raise(mrb, E_RUNTIME_ERROR, SDL_GetError()); SDL_QueryTexture(ptr->data, NULL, NULL, &ptr->width, &ptr->height); mrb_data_init(texture, ptr, &cg_texture_type); return texture; } mrb_value cg_cText_from_text(mrb_state *mrb, mrb_value self) { char *text; SDL_Surface *surface = NULL; mrb_bool background; struct mrb_value texture = texture_alloc(mrb, self); struct cg_color *tx_color_ptr, *bg_color_ptr; struct cg_font *font_ptr; struct cg_texture *ptr; mrb_get_args( mrb, "zdd|d?", &text, &font_ptr, &cg_font_type, &tx_color_ptr, &cg_color_type, &bg_color_ptr, &cg_color_type, &background); ptr = (struct cg_texture *)DATA_PTR(texture); if(ptr) mrb_free(mrb, ptr); ptr = (struct cg_texture *)mrb_malloc(mrb, sizeof(struct cg_texture)); // Create surface. if(background) surface = TTF_RenderUTF8_Shaded( font_ptr->data, text, tx_color_ptr->data, bg_color_ptr->data); else surface = TTF_RenderUTF8_Solid(font_ptr->data, text, tx_color_ptr->data); if(surface == NULL) mrb_raise(mrb, E_RUNTIME_ERROR, TTF_GetError()); // Convert the surface to a texture. ptr->data = SDL_CreateTextureFromSurface(cg_core.renderer, surface); SDL_FreeSurface(surface); if(ptr->data == NULL) mrb_raise(mrb, E_RUNTIME_ERROR, SDL_GetError()); SDL_QueryTexture(ptr->data, NULL, NULL, &ptr->width, &ptr->height); mrb_data_init(texture, ptr, &cg_texture_type); return texture; } static mrb_value cg_cTexture_width(mrb_state *mrb, mrb_value self) { struct cg_texture *ptr; ptr = (struct cg_texture *)DATA_PTR(self); return mrb_int_value(mrb, ptr->width); } static mrb_value cg_cTexture_height(mrb_state *mrb, mrb_value self) { struct cg_texture *ptr; ptr = (struct cg_texture *)DATA_PTR(self); return mrb_int_value(mrb, ptr->height); } static mrb_value cg_cTexture_draw(mrb_state *mrb, mrb_value self) { SDL_Rect dst_rect; struct cg_texture *ptr; struct cg_point *point; mrb_get_args(mrb, "d", &point, &cg_point_type); ptr = (struct cg_texture *)DATA_PTR(self); dst_rect.x = point->data.x; dst_rect.y = point->data.y; dst_rect.w = ptr->width; dst_rect.h = ptr->height; SDL_RenderCopy(cg_core.renderer, ptr->data, NULL, &dst_rect); return self; } static mrb_value cg_cTexture_draw_xy(mrb_state *mrb, mrb_value self) { SDL_Rect dst_rect; struct cg_texture *ptr; mrb_int x, y; mrb_get_args(mrb, "ii", &x, &y); ptr = (struct cg_texture *)DATA_PTR(self); dst_rect.x = x; dst_rect.y = y; dst_rect.w = ptr->width; dst_rect.h = ptr->height; SDL_RenderCopy(cg_core.renderer, ptr->data, NULL, &dst_rect); return self; } void cg_texture_init(mrb_state *mrb) { struct RClass *cg_m, *cg_cTexture; cg_m = mrb_module_get(mrb, "CandyGear"); cg_cTexture = mrb_define_class_under( mrb, cg_m, "Texture", mrb->object_class); MRB_SET_INSTANCE_TT(cg_cTexture, MRB_TT_DATA); mrb_undef_class_method(mrb, cg_cTexture, "new"); mrb_define_class_method( mrb, cg_cTexture, "from_image", cg_cTexture_from_image, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); mrb_define_class_method( mrb, cg_cTexture, "from_text", cg_cText_from_text, MRB_ARGS_REQ(3)|MRB_ARGS_OPT(1)); mrb_define_method( mrb, cg_cTexture, "width", cg_cTexture_width, MRB_ARGS_NONE()); mrb_define_method( mrb, cg_cTexture, "height", cg_cTexture_height, MRB_ARGS_NONE()); mrb_define_method( mrb, cg_cTexture, "draw", cg_cTexture_draw, MRB_ARGS_REQ(1)); mrb_define_method( mrb, cg_cTexture, "draw_xy", cg_cTexture_draw_xy, MRB_ARGS_REQ(2)); }